C++中的默认成员函数 现代写法
8个默认成员函数
6个编译器默认生成的成员函数
默认构造函数(Default Constructor)
- 作用:用于创建一个类的对象实例,不需要任何额外参数。当创建对象时,如果没有提供其他构造函数,或者没有明确使用其他构造函数进行初始化,就会调用默认构造函数。
拷贝构造函数(Copy Constructor)
- 作用:用于根据一个已存在的对象来创建一个新的对象实例,作为原对象的副本。它通常用于当一个对象需要以值传递的方式传递给函数,或者当对象需要被复制来初始化另一个对象时。
拷贝赋值运算符(Copy Assignment Operator)
- 作用:用于将一个已存在的对象赋值给另一个对象。这不同于拷贝构造函数,拷贝构造函数是在创建新对象时使用的,而拷贝赋值运算符是在对象已经存在时对其进行赋值操作。
析构函数(Destructor)
- 作用:在对象生命周期结束时被调用,用于释放对象可能占用的资源,并执行任何必要的清理工作。析构函数是在对象被销毁前自动调用的,确保资源的正确释放,防止内存泄漏。
移动构造函数(Move Constructor,C++11 引入) —— 并不看做默认成员
- 作用:允许将一个对象(通常是临时对象或即将被销毁的对象)的资源“移动”到另一个新创建的对象中,而不是复制资源。这可以显著提高性能,特别是在处理大量数据或资源密集型对象时。
移动赋值运算符(Move Assignment Operator,C++11 引入)—— 并不看做默认成员
- 作用:类似于移动构造函数,但用于已存在的对象之间的赋值操作。它允许一个对象的资源被“移动”到另一个已存在的对象中,而不是进行传统的复制赋值操作。
取地址重载(Address-of Operator Overloading)
- 作用:这不是一个默认生成的成员函数,但可以通过重载operator&来提供自定义的地址获取行为。这允许开发者在返回对象地址时执行额外的逻辑或安全检查。
const取地址重载
- 作用:当对象被声明为const时,可以通过重载const版本的取地址运算符(例如,operator&() const)来提供获取const对象地址的特定行为。这确保了即使对象是常量,也能以安全且符合预期的方式获取其地址。这种重载通常用于确保对const对象的操作不会修改对象的状态或违反其常量性质。
取地址重载和const取地址重载并不是编译器默认生成的成员函数,而是我们根据需要显式定义的。这些重载函数允许更精细地控制对象地址的获取方式。
初始化和清理
- 构造完成初始化。
- 析构函数完成清理。
由于多态的原因,所有析构函数的函数名都被处理为了destructor,所以在派生类调用基类的析构时,需要指定基类域——但都使用自动调用,用于保证析构顺序。
析构函数处理为多态的原因
- 需要给析构函数加上virtual。
- 所有的析构函数都被处理为destructor(),所以他们满足重写的条件
delete p
可以看作p->destructor()
满足指针或者引用调用的条件。(具体查看多态)
所以,一个类如果要被继承,那么它的析构函数就需要用virtual
修饰,形成析构函数的多态。
拷贝构造
拷贝构造用于同类对象初始化创建对象,是构造函数的一种重载形式。使用const防止
拷贝构造的参数只有一个且必须是拷贝对象的引用,如果使用传值的方式,编译器将直接报错,因为会引发无穷递归调用。
赋值拷贝
图中为了防止隐藏,要指定在基类person::
注意事项:
- 已经存在的两个对象之间赋值拷贝——运算符重载函数。赋值重载主要是吧一个对象赋值给另一个对象。
- 参数类型为const T&,传递引用可以提高传参效率。
- 返回类型为:T&,有返回值的目的是为了支持连续赋值。
- 检查是否自己给自己赋值,一般比较地址(为了提高效率)。
- 返回*This:符合连续赋值的含义。
- 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,所以不可将赋值运算符重载定义为全局的函数,避免在使用时的不明确。
取地址重载
- 普通对象取地址。
- const对象取地址。
“现代写法”
在这里的表现为在拷贝构造当中调用构造函数。
移动构造
如果没有自己实现移动构造,并且没有实现析构函数,拷贝构造,拷贝赋值,(三个都没有)那么编译器会尝试自动生成一个移动构造。
- 对于内置类型,则执行逐成员的字节拷贝。
- 对于自定义类型来说
- 如果实现移动构造,那么就调用它。
- 如果没有实现移动构造,那么就去调用拷贝构造。
强制生成成员函数
可以通过 = default 语法来实现——如下:
1 |
|
C++中的默认成员函数 现代写法
https://weihehe.top/2024/07/03/C-中的默认成员函数/