5. 显式默认函数和显式删除函数

在 C++11 及之后的标准中,delete 和 default 两个关键字可以用于指示编译器对特殊成员函数(构造函数、拷贝构造函数、拷贝赋值函数、析构函数、移动构造函数、移动赋值函数)进行管理的关键字。

它们的作用如下:

语法格式服下:

class 类名 {
    public:
        // 让编译器生成某个默认的特殊成员函数
        特殊成员函数名() = default;
        // 让编译器删除特殊成员函数。
        特殊成员函数名() = delete;
        // 删除对  double 类型的函数的重载。
        返回类型 普通成员函数名(实参列表) = delete;
};

5.1 =default 显式默认函数

=default 关键字用于显式生成默认的特殊成员函数。

C++11 的类内有六个特殊成员函数,这六个函数的功能如下:

  1. 无参的构造函数:默认不执行任何操作,如果重载其构造函数则此无参的构造函数将丢失(不生成此成员函数)。
  2. 拷贝构造函数:默认成员变量之间依次赋值(浅拷贝)。
  3. 拷贝赋值函数:默认成员变量之间依次赋值(浅拷贝)。
  4. 析构函数:默认不执行任何操作。
  5. 移动构造函数:默认成员变量之间移动赋值。
  6. 移动赋值函数:默认成员变量之间移动赋值。

示例1

如果重载其构造函数 Complex(double, double) 则无参的构造函数 Complex(void) 将不再自动生成。因此不能以无参数的方式创建对象。如下所示:

// filename: default1.cpp
class Complex {
    public:
        Complex(double r, double i): real(r), image(i){}
   private:
        double real;
        double image;
};

int main(int argc, char * argv[]) {
    Complex c1(1, 2);
    Complex c2;  // 报错

    return 0;
}

编译时报错结果如下:

weimz@mzstudio:~$ g++ -o default1 default1.cpp
default1.cpp: In function ‘int main(int, char**)’:
default1.cpp:12:13: error: no matching function for call to ‘Complex::Complex()’
   12 |     Complex c2;  // 报错
      |             ^~
default1.cpp:12:13: note: there are 3 candidates
default1.cpp:4:9: note: candidate 1: ‘Complex::Complex(double, double)’
    4 |         Complex(double r, double i): real(r), image(i){}
      |         ^~~~~~~
default1.cpp:4:9: note: candidate expects 2 arguments, 0 provided
default1.cpp:2:7: note: candidate 2: ‘constexpr Complex::Complex(const Complex&)’
    2 | class Complex {
      |       ^~~~~~~
default1.cpp:2:7: note: candidate expects 1 argument, 0 provided
default1.cpp:2:7: note: candidate 3: ‘constexpr Complex::Complex(Complex&&)’
default1.cpp:2:7: note: candidate expects 1 argument, 0 provided
default1.cpp:12:13: warning: unused variable ‘c2’ [-Wunused-variable]
   12 |     Complex c2;  // 报错
      |             ^~
make: *** [Makefile:35:default1] 错误 1

示例2

使用 =default 为 Complex 类添加无参数的构造函数,可以让其以无参数的方式创建对象,但对象内的成员变量可能不被初始化(栈和堆上创建时)。

// filename: default2.cpp
class Complex {
    public:
        Complex(double r, double i): real(r), image(i){}
        Complex() = default;
   private:
        double real;
        double image;
};

int main(int argc, char * argv[]) {
    Complex c1(1, 2);
    Complex c2;  // 无报错

    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o default2 default2.cpp
weimz@mzstudio:~$ ./default2
weimz@mzstudio:~$

编译无措,无任何输出。

以上示例都是默认成员函数类内声明、类内定义的用法。

在使用 =default 生成默认特殊成员函数时也可以类内声明、类外定义的方式实现(推荐)。

=default 类内声明、类外定义的语法

class 类名 {
    public:
        返回类型 特殊成员函数(形参列表);   // 类内声明
};

// 类外实现
返回类型 类名::特殊成员函数(形参列表) = default;   // 类外定义

示例3

使用 =default 为 Complex 类添加无参数的构造函数,使用类内声明,类外定义的方式实现。

// filename: default3.cpp
class Complex {
    public:
        Complex(double r, double i): real(r), image(i){}
        Complex();  // 类内声明
   private:
        double real;
        double image;
};

Complex::Complex() = default;  // 类外定义

int main(int argc, char * argv[]) {
    Complex c1(1, 2);
    Complex c2;  // 无报错

    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o default3 default3.cpp
weimz@mzstudio:~$ ./default3
weimz@mzstudio:~$

以上程序语法正确,无报错。