C++类的默认函数简介

在C++类中,一共有8个默认函数:

class A
{
public:
    A();                            // 默认构造函数
    ~A();                           // 默认析构函数
    A(const A&);                    // 默认拷贝构造函数
    A& operator = (const A&);       // 默认重载赋值运算符函数
    A* operator & ();               // 默认取地址运算符函数
    const A* operator & () const;   // 默认重载取地址运算符const函数
    A(A&&);                         // 默认移动构造函数
    A& operator = (const A&&);      // 默认重载移动赋值操作符函数
};

如果只是声明一个空类,不做任何事情的话,编译器会自动生成一个默认构造函数、一个默认拷贝构造函数、一个默认重载赋值运算符函数以及一个默认析构函数。这些默认函数只有在第一次被调用时,才会被编译器创建,当然这几个函数其实啥也没做,所以它们是inline和public的。

C++11中新增了几个关键字和默认函数相关:

  • default:被标识的默认函数将使用类的默认行为,比如:A() = default
  • delete:被标识的默认函数将被禁用,比如:A() = delete
  • override:被标识的函数需要强制重写基类虚函数
  • final:被标识的函数禁止重写基类函数

一、构造函数

  • 作用是初始化对象,在堆上new一个对象或者在栈上定义一个临时对象时,会自动调用对象的构造函数。
  • 初始化的方式分为两种,一种是初始化列表,一种是在构造函数体中赋值。初始化列表方式更加高效,减少了一次赋值操作,推荐此方法。
  • 常量成员变量、引用类型成员变量、没有缺省构造函数变量等必须写在初始化列表中。
  • 构造函数不能是虚函数。
  • 在构造函数的函数体中可以使用this指针,但在初始化列表中不能使用this(原因是对象还未创建,没有this指针)。
  • 对于单参构造函数,为了防止不必要的隐式转换,通常在构造函数前加上explicit关键字。
  • 对于有继承关系的类对象的构造顺序是:先构造基类,再构造派生类。

二、拷贝构造函数

  • 拷贝构造函数其实就是构造函数的重载,具备构造函数的一切特征。
  • 拷贝构造函数是用已有的对象构造新的对象。
  • 拷贝构造函数的参数类型是固定的,不能随意修改。
  • 针对带指针成员变量的类来说,拷贝构造函数可能存在浅拷贝和深拷贝的问题,浅拷贝可能带来程序的崩溃,在类对象被析构的时候,发生了多次delete同一个地址的问题。

三、析构函数

  • 析构函数主要做一些清理工作,比如数据库类的析构函数用于关闭数据库连接。
  • 析构函数一般会写成虚析构函数,主要是虚析构函数会自动调用父类的析构函数(如果有继承关系的话),这样可以避免可能存在的内存泄露问题。
  • 析构顺序与构造顺序相反,如果有继承关系的话,先析构子类,再析构父类。

四、重载赋值运算符函数

  • 赋值运算符重载函数发生在类对象之间赋值的时候,而不是初始化的时候:
class A
{
    ...
};

A a;
A b = a;    // 这里调用的是拷贝构造函数,相当于 A b(a);
A c;
c = a;      // 这里调用的是赋值运算符重载函数,相当于 c.operator =(a)
  • 重载赋值运算符函数参数中没有强制要求const 和 &,返回值是类对象的引用,所以可以实现链式赋值操作,比如:a = b = c; 如果返回值类型设置为void,就不能进行链式赋值操作。

五、重载取地址运算符(const/非const)函数

  • 重载取地址运算符函数没有参数
  • 如果没有显式定义,编译器会自动生成默认的重载取地址运算符函数,函数内部直接 ruturn this;

六、移动构造函数和重载移动赋值操作符函数

  • C++11新增了move语义:源对象资源的控制权全部交给目标对象,可以将源对象移动到新对象,用于a初始化b后,就将a析构的情况。
  • 移动构造函数的参数和拷贝构造函数的参数不同,移动构造函数的参数是右值引用(&&),拷贝构造函数的参数是左值引用(&)。
  • 移动构造函数主要是用来较少不必要的复制,带来性能上的提升。

你可能感兴趣的:(C++进阶教程,c++)