1. 构造函数:
(1)成员初始化顺序
成员初始化顺序必须与他们在类定义中的出现顺序一致,而不是在初始值中出现的顺序
(2)必须初始化的情况:
const成员和引用成员必须初始化
2. 默认构造函数
(1)编译器帮助
不定义构造函数时,编译器自动产生默认构造函数
(2)重定义警告
不可以同时定义有参和无参的默认构造函数
3. 复制构造函数
调用复制构造函数的三种情况
1) 定义新对象以老对象作为复制
2) 以函数形式参数传入类的对象
3) 函数的返回值是类的对象
4. 析构函数
(1)功能
自动调用完成清理工作 调用后对象消失 内存释放
(2)特性
无函数类型 无参数 不能重载
5. 移动构造函数
(1)左值与右值引用
#include <iostream>
using namespace std;
int main() {
float n = 6;
float &lr_n = n; // 左值引用
float &&rr_n = n * n; // 右值表达式绑定到右值引用
//float &&rr_n2 = n; 错误,右值引用不能绑定到左值
//
float &&rr_n2 = std::move(n); //将n转化为右值
return 0;
}
(2)定义移动构造函数
a. 函数签名
移动构造函数的参数是右值引用
b. 函数体实现
在函数体中将资源从被引用的对象转向引用的对象;如果类中有指针成员,需将指针置空,避免被释放两次
c. 注意事项
要确保移动后的源对象处于有效但可能未定义的状态,这样源对象的析构函数能正确执行且不会发生错误
class Myclass{
int *data;
int size;
public:
Myclass(Myclass&& other){
data=other.data;
size=other.size;
other.data=nullptr;
other.size=0;
}
};
(3)调用移动构造函数
a. 返回值优化场景
当函数返回一个局部对象时,编译器可能会利用移动构造函数来避免不必要的复制
Myclass createObject(){
Myclass temp;
初始化temp
//
return temp;
}
int main()
{
Myclass newObj=createObject();
//这里会调用移动构造函数将createObject函数中的临时对象temp的资源移动到newObj
return 0;
}
b. 使用std::move显示调用
若有一个左值(可以取地址的对象),但想将其当做右值来使用,从而调用移动构造函数,可以使用std::move函数。调用std::move后,原来的对象可能处于一种被移动后的不确定状态
Myclass Obj1;// 初始化Obj1
Myclass Obj2=std::move(Obj1);
// 移动构造函数将Obj1的资源移动到Obj2,Obj1的状态可能不符合预期,在使用Obj1之前可能需要重
新初始化
6. default、delete函数
=default:要求编译器生成默认或复制构造函数=delete:要求编译器删除指定函数,除析构函数之外均可以删除