C++学习:类和对象(二)
一、默认成员函数
1. 什么是默认成员函数?
在C++中,每个类都有一些特殊的成员函数,如果程序员没有显式地声明,编译器会自动为类生成这些函数,这些函数称为默认成员函数
2. 默认成员函数列表
- 默认构造函数(Default Constructor)
- 默认析构函数(Destructor)
- 默认拷贝构造函数(Copy Constructor)
- 默认拷贝赋值运算符(Copy Assignment Operator)
- 默认移动构造函数(Move Constructor,C++11引入)
- 默认移动赋值运算符(Move Assignment Operator,C++11引入)
3. 编译器何时生成默认成员函数?
- 显式声明:如果程序员没有提供某个默认成员函数的定义,编译器会根据需要自动生成
- 特别注意:一旦程序员显式地声明了任何一个拷贝或移动操作,编译器将不会为该类生成移动操作,需要手动提供
4. 代码示例
#include <iostream>
using namespace std;class Example {
public:int value;// 未显式声明任何默认成员函数
};int main() {Example ex1; // 调用默认构造函数ex1.value = 10;Example ex2 = ex1; // 调用默认拷贝构造函数Example ex3;ex3 = ex1; // 调用默认拷贝赋值运算符cout << "ex1.value = " << ex1.value << endl;cout << "ex2.value = " << ex2.value << endl;cout << "ex3.value = " << ex3.value << endl;return 0;
}
二、构造函数
1. 什么是构造函数?
构造函数(Constructor)是在创建对象时自动调用的特殊成员函数,用于初始化对象的成员变量。构造函数的名称与类名相同
2. 特点
- 没有返回类型(连
void也没有) - 可以有参数(参数化构造函数)
- 支持函数重载,即可以有多个构造函数
- 可以在构造函数初始化列表中初始化成员变量
3. 默认构造函数
如果程序员未提供任何构造函数,编译器会为类生成一个默认构造函数,它对基本类型成员变量不进行初始化
4. 代码示例:
1.默认构造函数
#include <iostream>
using namespace std;class Person {
public:string name;int age;// 默认构造函数Person() {name = "Unknown";age = 0;}void display() const {cout << "姓名:" << name << ", 年龄:" << age << endl;}
};int main() {Person p; // 调用默认构造函数p.display();return 0;
}
2.参数化构造函数
#include <iostream>
using namespace std;class Person {
public:string name;int age;// 参数化构造函数Person(const string& n, int a) {name = n;age = a;}void display() const {cout << "姓名:" << name << ", 年龄:" << age << endl;}
};int main() {Person p("Alice", 25); // 调用参数化构造函数p.display();return 0;
}
3.构造函数初始化列表
#include <iostream>
using namespace std;class Point {
private:int x;int y;public:// 使用初始化列表初始化成员变量Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {}void display() const {cout << "坐标:(" << x << ", " << y << ")" << endl;}
};int main() {Point pt(3, 4);pt.display();return 0;
}
5. 注意事项
- 如果类中有
const成员变量或引用类型成员,必须使用初始化列表进行初始化 - 构造函数可以被重载,允许创建多个具有不同参数列表的构造函数
三、析构函数
1. 什么是析构函数?
析构函数(Destructor)是在对象生命周期结束时自动调用的特殊成员函数,用于释放对象占用的资源(如内存、文件等)。析构函数的名称是在类名前加上~符号
2. 特点
- 没有参数
- 没有返回类型
- 每个类只有一个析构函数,不能重载
- 编译器会自动调用析构函数,无需手动调用
3. 代码示例
#include <iostream>
using namespace std;class Resource {
public:Resource() {cout << "资源已分配。" << endl;}~Resource() {cout << "资源已释放。" << endl;}
};int main() {cout << "进入main函数。" << endl;{Resource res; // 创建对象,调用构造函数} // 离开作用域,调用析构函数cout << "退出main函数。" << endl;return 0;
}
4. 在析构函数中释放资源
当类中使用了动态内存分配(如使用new关键字),需要在析构函数中释放内存,防止内存泄漏
#include <iostream>
using namespace std;class Array {
private:int* data;int size;public:Array(int s) : size(s) {data = new int[size];cout << "数组已分配。" << endl;}~Array() {delete[] data;cout << "数组已释放。" << endl;}
};int main() {Array arr(10);// 使用数组...return 0;
}
5. 注意事项
- 析构函数必须为公有成员函数,否则对象在离开作用域时无法正确销毁
- 避免在析构函数中抛出异常,这可能导致程序不可预测的行为
四、拷贝构造函数
1. 什么是拷贝构造函数?
拷贝构造函数(Copy Constructor)是使用同类的另一个对象来初始化新对象时调用的构造函数。它用于定义对象的拷贝行为
2. 语法
ClassName(const ClassName& other);
参数为同类对象的引用,通常为const引用,避免不必要的拷贝
3. 默认拷贝构造函数
- 如果程序员未提供拷贝构造函数,编译器会自动生成默认的拷贝构造函数,执行浅拷贝
- 对于没有动态内存分配的类,默认的拷贝构造函数通常够用
4. 浅拷贝与深拷贝
- 浅拷贝(Shallow Copy):拷贝对象的成员变量值,对于指针成员,仅拷贝指针值,两个对象指向同一内存位置
- 深拷贝(Deep Copy):在拷贝指针成员时,为新对象分配独立的内存空间,并复制内容
5. 示例
1.默认拷贝构造函数(浅拷贝)
#include <iostream>
using namespace std;class Shallow {
public:int* data;Shallow(int val) {data = new int(val);}~Shallow() {delete data;}
};int main() {Shallow obj1(5);Shallow obj2 = obj1; // 调用默认拷贝构造函数cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 10;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}
问题:
由于是浅拷贝,obj1和obj2的data指向同一内存,当一个对象被析构时,内存被释放,另一个对象再使用时会导致悬空指针
2.自定义拷贝构造函数(深拷贝)
#include <iostream>
using namespace std;class Deep {
public:int* data;Deep(int val) {data = new int(val);}// 自定义拷贝构造函数Deep(const Deep& other) {data = new int(*(other.data));}~Deep() {delete data;}
};int main() {Deep obj1(5);Deep obj2 = obj1; // 调用自定义拷贝构造函数cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 10;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}
6. 注意事项
- 拷贝构造函数的参数必须是引用,否则会导致无限递归
- 当类中有指针成员,且需要独立的内存空间,必须提供自定义的拷贝构造函数(深拷贝)
五、赋值运算符函数
1. 什么是赋值运算符函数?
赋值运算符函数(Assignment Operator Function)用于定义对象间赋值行为(operator=)。类似于拷贝构造函数,它也需要考虑浅拷贝和深拷贝
2. 语法
ClassName& operator=(const ClassName& other);
- 返回类型为引用,返回当前对象自身
*this,以支持链式赋值 - 参数为同类对象的**
const引用**
3. 默认赋值运算符
- 如果程序员未提供赋值运算符函数,编译器会生成默认的赋值运算符,执行浅拷贝
4. 示例
1.默认赋值运算符(浅拷贝)
#include <iostream>
using namespace std;class Shallow {
public:int* data;Shallow(int val) {data = new int(val);}~Shallow() {delete data;}
};int main() {Shallow obj1(5);Shallow obj2(10);obj2 = obj1; // 使用默认赋值运算符cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 15;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}
2.自定义赋值运算符函数(深拷贝)
#include <iostream>
using namespace std;class Deep {
public:int* data;Deep(int val) {data = new int(val);}Deep(const Deep& other) {data = new int(*(other.data));}// 自定义赋值运算符函数Deep& operator=(const Deep& other) {if (this == &other) {return *this; // 检查自赋值}delete data; // 释放原有内存data = new int(*(other.data)); // 分配新内存并拷贝return *this;}~Deep() {delete data;}
};int main() {Deep obj1(5);Deep obj2(10);obj2 = obj1; // 使用自定义赋值运算符cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 15;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}
5. 注意事项
- 检查自赋值:在赋值运算符函数中,应检查
this和other是否为同一对象,避免释放自己 - 释放原有资源:在进行赋值前,应释放对象原有的资源,防止内存泄漏
- 返回
*this的引用,支持链式赋值
六、const成员函数
1. 什么是const成员函数?
const成员函数是指在函数声明后加上const关键字的成员函数,表示该函数不会修改对象的成员变量(除非成员变量被声明为mutable)
2. 语法
返回类型 函数名(参数列表) const;
3. 特点
const成员函数只能调用其他const成员函数,不能调用非const成员函数- 可以被
const对象调用,而非const成员函数不能被const对象调用
4. 代码示例
#include <iostream>
using namespace std;class Sample {
private:int value;public:Sample(int v) : value(v) {}int getValue() const {return value;}void setValue(int v) {value = v;}
};int main() {const Sample s(10); // 常量对象cout << "值是:" << s.getValue() << endl;// s.setValue(20); // 错误,不能调用非const成员函数return 0;
}
5. const对象和成员函数
- **
const对象:**对象被声明为const,只能调用其const成员函数,不能修改成员变量 - **非
const对象:**可以调用所有成员函数,包括const和非const
6. 成员函数重载
可以根据const性对成员函数进行重载
代码示例:
#include <iostream>
using namespace std;class Example {
public:void func() {cout << "非const版本的func()" << endl;}void func() const {cout << "const版本的func()" << endl;}
};int main() {Example e;e.func(); // 调用非const版本const Example ce;ce.func(); // 调用const版本return 0;
}
七、取地址及const取地址操作符重载
1. 取地址操作符operator&
默认情况下,对象的取地址操作会返回对象的内存地址。可以通过重载operator&来改变取地址操作的行为
2. 为什么需要重载取地址操作符?
- 在某些情况下,我们希望隐藏对象的内部地址,或提供特殊的地址计算方式
- 可以用于智能指针的实现
3. 语法
ClassName* operator&();
const ClassName* operator&() const;
4. 示例
1.重载取地址操作符
#include <iostream>
using namespace std;class MyClass {
public:int value;MyClass(int v) : value(v) {}// 重载取地址操作符MyClass* operator&() {cout << "自定义取地址操作符被调用。" << endl;return this;}// 重载const版本const MyClass* operator&() const {cout << "自定义const取地址操作符被调用。" << endl;return this;}
};int main() {MyClass obj(10);MyClass* ptr = &obj; // 调用自定义取地址操作符cout << "value = " << ptr->value << endl;const MyClass cobj(20);const MyClass* cptr = &cobj; // 调用自定义const取地址操作符cout << "const value = " << cptr->value << endl;return 0;
}
5. 注意事项
- 小心使用:重载取地址操作符可能导致代码难以理解和维护,应该谨慎使用
- 避免陷阱:重载后,可能会影响模板代码或标准库的使用,需要确保兼容性
相关文章:
C++学习:类和对象(二)
一、默认成员函数 1. 什么是默认成员函数? 在C中,每个类都有一些特殊的成员函数,如果程序员没有显式地声明,编译器会自动为类生成这些函数,这些函数称为默认成员函数 2. 默认成员函数列表 默认构造函数(…...
深度学习(五):语音处理领域的创新引擎(5/10)
一、深度学习在语音处理中的崛起 在语音处理领域,传统方法如谱减法、维纳滤波等在处理复杂语音信号时存在诸多局限性。这些方法通常假设噪声是平稳的,但实际噪声往往是非平稳的,导致噪声估计不准确。同时,为了去除噪声࿰…...
双曲函数(Hyperbolic functuons)公式
在python等语言里有双曲函数库和反双曲函数库,但是并没有包含所有的双曲函数。以numpy为例子,numpy只提供了sinh、cosh、tanh、arcsinh、arccosh、arctanh六种函数,那么其余的就需要用公式计算了。 转换公式 对于函数库不能直接计算的&#…...
【CSS/SCSS】@layer的介绍及使用方法
目录 基本用法layer 的作用与优点分离样式职责,增强代码可读性和可维护性防止无意的样式冲突精确控制样式的逐层覆盖提高复用性 兼容性实际示例:使用 import 管理加载顺序实际示例:混入与 layer 结合使用 layer 是 CSS 中用于组织和管理样式优…...
我为什么投身于青少年AI编程?——打造生态圈(三)
第五部分 青少年AI编程生态圈 一、生态圈 主要涵盖家庭、社区/中小学、高校高职、主管部门。 1、家庭 我们与社区/中小学一道打造让家长满意的模式。 教得好: 费用少: 家门口: 2、社区/中小学 社区党群服务中心和中小学都有大面积科普…...
出海要深潜,中国手机闯关全球化有了新标杆
经济全球化的大势之下,中国科技企业开拓海外市场已成为一种必然选择。 对于国内手机企业来说,推进全球商业版图扩张,业务潜力巨大,海外市场是今后的关键增长引擎。 当前中国手机厂商在海外市场的发展,有收获也有坎坷…...
百度SEO中的关键词密度与内容优化研究【百度SEO专家】
大家好,我是百度SEO专家(林汉文),在百度SEO优化中,关键词密度和关键词内容的优化对提升页面排名至关重要。关键词的合理布局与内容的质量是确保网页在百度搜索结果中脱颖而出的关键因素。下面我们将从关键词密度和关键…...
如何用fastapi集成pdf.js 的viewer.html ,并支持 mjs
fastapi 框架 集成pdf.js 的 viewer.html?file=***,支持跨域,支持.mjs .wasm .pdf 给出完整示例代码 要在 FastAPI 框架中集成 pdf.js 的 viewer.html,并支持跨域访问以及 .mjs、.wasm、.pdf 文件的正确加载,可以按照以下步骤进行。下面提供一个完整的示例,包括项目结构…...
文件相对路径与绝对路径
前言: 在写代码绘制图像的过程中,发现出现cant read input file的异常,而且输出框没有绘制图片,所以寻找解决方案。先贴上之前写的简洁版绘制图像代码 1.BackGround类 import java.awt.image.BufferedImage;public class BackG…...
Linux 重启命令全解析:深入理解与应用指南
Linux 重启命令全解析:深入理解与应用指南 在 Linux 系统中,掌握正确的重启命令是确保系统稳定运行和进行必要维护的关键技能。本文将深入解析 Linux 中常见的重启命令,包括功能、用法、适用场景及注意事项。 一、reboot 命令 功能简介 re…...
【北京迅为】《STM32MP157开发板嵌入式开发指南》-第六十七章 Trusted Firmware-A 移植
iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐…...
`a = a + b` 与 `a += b` 的区别
在 Java 中,a a b 和 a b 都用于将 b 的值加到 a 上,但它们之间存在一些重要的区别,尤其是在类型转换和操作行为方面。 使用 操作符时,Java 会自动进行隐式类型转换,而使用 则不会。这意味着在 a b 的情况下&am…...
mysqld.log文件过大,清理后不改变所属用户
#1024程序员节# 一、背景 突然有一天,我的mysql报磁盘不足了。仔细查看才发现,是磁盘满了。而MySQL的日志文件占用了91个G.如下所示: [roothost-172-16-14-128 mysql]# ls -lrth 总用量 93G -rw-r----- 1 mysql mysql 1.1G 7月 30 2023 m…...
v4.7+版本用户充值在交易统计中计算双倍的问题修复
app/services/statistic/TradeStatisticServices.php 文件中 $whereInRecharge[recharge_type] no_system; $whereInRecharge[recharge_type] system; app/model/user/UserRecharge.php 中 修改此搜索器内容 public function searchRechargeTypeAttr($query, $value){ if…...
[GXYCTF 2019]Ping Ping Ping 题解(多种解题方式)
知识点: 命令执行 linux空格绕过 反引号绕过 变量绕过 base64编码绕过 打开页面提示 "听说php可以执行系统函数?我来康康" 然后输入框内提示输入 bjut.edu.cn 输入之后回显信息,是ping 这个网址的信息 输入127.0.0.1 因为提示是命令…...
MODSI EVI 数据的时间序列拟合一阶谐波模型
目录 简介 函数 ee.Reducer.linearRegression(numX, numY) Arguments: Returns: Reducer ee.Image.cat(var_args) Arguments: Returns: Image hsvToRgb() Arguments: Returns: Image 代码 结果 简介 MODIS/006/MOD13A1数据是由美国国家航空航天局(NASA)的MODIS…...
Java:String类(超详解!)
一.常用方法 🥏1.字符串构造 字符串构造有三种方法: 📌注意: 1. String是引用类型,内部并不存储字符串本身 如果String是一个引用那么s1和s3应该指向同一个内容,s1和s2是相等的,应该输出两…...
【日志】力扣13.罗马数字转整数 || 解决泛型单例热加载失败问题
2024.10.28 【力扣刷题】 13. 罗马数字转整数 - 力扣(LeetCode)https://leetcode.cn/problems/roman-to-integer/description/?envTypestudy-plan-v2&envIdtop-interview-150这题用模拟的思想可以给相应的字母赋值,官方的答案用的是用一…...
Mybatis高级
系列文章目录 高级Mybatis,一些结果映射,引入新的注解 目录 系列文章目录 文章目录 一、结果映射 1.ResultType 2.ResultMap 基础应用: 二、一对一 嵌套结果和嵌套查询 嵌套结果 嵌套查询 区别 三、一对多 四、多对多 五、注解补充 1.一对一…...
【spark】spark structrued streaming读写kafka 使用kerberos认证
spark版本:2.4.0 官网 Spark --files使用总结 Spark --files理解 一、编写jar import org.apache.kafka.clients.CommonClientConfigs import org.apache.kafka.common.config.SaslConfigs import org.apache.spark.sql.SparkSession import org.apache.spark.sql.streaming.T…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
