1.构造函数
1.1 特点
① 函数名与类名相同;② 没有返回值;③ 没有返回类型(包括void型)
1.2 调用
- 创建类对象时自动调用,显式调用会创建对象
- 若没有定义,编译器会自动生成;若已经有定义则不会提供,此时如果还想创建无参对象需写出默认构造函数
- 可以重载
- 初始化数据成员的顺序要与其被定义的顺序一致,与初始化列表的顺序无关
- 不能使用类名.函数的形式调用,可以直接调用
2.析构函数
2.1 特征
① 函数名 = ~ + 类名;② 无参,无返回类型,故不可重载,函数唯一。
2.2 被调用时机
无论何时一个对象被销毁,就会自动调用其析构函数。
- 变量在离开其作用域时被销毁。
- 当一个对象被销毁时,其成员被销毁。
- 容器(无论是标准库容器还是数组)被销毁时,其元素被销毁。
- 对于动态分配的对象,当对指向他的指针应用delete时被销毁。
- 对于临时对象,当创建它的完整表达式结束时被销毁。
3. 注意
- 由于析构函数自动运行,程序可以按需分配资源而无需担心何时释放。
- 当一个类未定义自己的析构函数时,编译器会为它定义一个合成析构函数。
- 析构函数体本身并不直接销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的。
- 析构函数可以显式调用(不建议)
3. 拷贝构造函数
3.1 特点
编译器默认生成:ClassName ( const ClassName &rhs)
3.2 被调用时机
- 用一个已初始化的对象初始化刚创建的对象;
- 实参和形参均为类类型,当实参与形参结合时;
- 函数的返回类型为类类型,执行return语句时。
3.3 深拷贝和浅拷贝
- 浅拷贝只拷贝指针,一个对象被销毁会导致另一个对象无法获取其中数据,且可能会出现同一区域二次释放问题。
- 深拷贝拷贝指针所指向的内容,两个对象都拥有独立的空间存储数据。
3.4 左值和右值
- 左值:可以进行取地址
- 右值:不可以取地址(临时变量,临时对象,字面值常量)
- NOITCE: const引用既可以绑定左值也可以绑定右值,而非const引用无法识别右值
3.5 引用符号和const关键字
Q: 参数中的&能删除吗?
A: 不能。如果删除引用符号,则调用拷贝构造函数时出现“实参=形参”的情况,符合拷贝构造函数调用条件,会循环调用该函数,产生死循环,最后导致栈溢出。
Q: 参数中的const关键字能删除吗?
A: 不能。如果删除const关键字,当传递的参数为右值时,非const引用无法将其识别。
4. 赋值运算符函数
4.1 this指针
- 实质:指向对象本身的指针,是指针常量
- 位置:隐藏在每一个非静态成员函数的第一个参数
4.2 函数的使用
返回类型 类名::operator=(参数列表)
- 自复制(防止自己赋值给自己)
- 释放左操作数(防止内存泄漏)
- 深拷贝(防止访问越界)
- 返回
4.3 注意
Q: 参数中的引用符号能删除吗?
A:不能。如果去掉在调用函数时出现“实参=形参”的形式,满足拷贝构造函数的调用时机,会多调用一次拷贝构造函数,降低程序运行效率。
Q: 参数中的cons关键字能删除吗?
A:不能。如果去掉可能无法识别出右值。
Q: 函数返回类型中的引用符号能删除吗?
A:不能。如果去掉则返回类类型对象,满足拷贝构造函数的调用时机,会多调用一次拷贝构造函数,降低程序运行效率。
Q: 函数返回类型可以不是类类型吗?
A:不能。如果去掉则无法实现连续赋值。
5.