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取地址重载并不是编译器默认生成的成员函数,而是我们根据需要显式定义的。这些重载函数允许更精细地控制对象地址的获取方式。

初始化和清理

  1. 构造完成初始化。
  2. 析构函数完成清理。

由于多态的原因,所有析构函数的函数名都被处理为了destructor,所以在派生类调用基类的析构时,需要指定基类域——但都使用自动调用,用于保证析构顺序。

析构函数处理为多态的原因

**导致内存泄漏**

  1. 需要给析构函数加上virtual
  2. 所有的析构函数都被处理为destructor(),所以他们满足重写的条件
  3. delete p可以看作p->destructor()满足指针或者引用调用的条件。(具体查看多态)

所以,一个类如果要被继承,那么它的析构函数就需要用virtual修饰,形成析构函数的多态。

拷贝构造

拷贝构造

  1. 拷贝构造用于同类对象初始化创建对象,是构造函数的一种重载形式。使用const防止

  2. 拷贝构造的参数只有一个且必须是拷贝对象的引用,如果使用传值的方式,编译器将直接报错,因为会引发无穷递归调用。

赋值拷贝

upload successful
图中为了防止隐藏,要指定在基类person::

注意事项:

  1. 已经存在的两个对象之间赋值拷贝——运算符重载函数。赋值重载主要是吧一个对象赋值给另一个对象。
  2. 参数类型为const T&,传递引用可以提高传参效率。
  3. 返回类型为:T&,有返回值的目的是为了支持连续赋值。
  4. 检查是否自己给自己赋值,一般比较地址(为了提高效率)。
  5. 返回*This:符合连续赋值的含义。
  6. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,所以不可将赋值运算符重载定义为全局的函数,避免在使用时的不明确。

取地址重载

  1. 普通对象取地址。
  2. const对象取地址。

“现代写法”

现代写法
在这里的表现为在拷贝构造当中调用构造函数。

移动构造

  • 如果没有自己实现移动构造,并且没有实现析构函数拷贝构造拷贝赋值,(三个都没有)那么编译器会尝试自动生成一个移动构造。

    • 对于内置类型,则执行逐成员的字节拷贝。
    • 对于自定义类型来说
      • 如果实现移动构造,那么就调用它。
      • 如果没有实现移动构造,那么就去调用拷贝构造。

强制生成成员函数

可以通过 = default 语法来实现——如下:

1
2
3
4
5
6
class MyClass {
public:
// 默认生成拷贝构造函数
MyClass(const MyClass&) = default;
};


C++中的默认成员函数 现代写法
https://weihehe.top/2024/07/03/C-中的默认成员函数/
作者
weihehe
发布于
2024年7月3日
许可协议