5. 显式默认函数和显式删除函数
在 C++11 及之后的标准中,delete 和 default 两个关键字可以用于指示编译器对特殊成员函数(构造函数、拷贝构造函数、拷贝赋值函数、析构函数、移动构造函数、移动赋值函数)进行管理的关键字。
它们的作用如下:
=default用于显式要求编译器生成默认版本的函数。=delete:用于指示编译器禁止生成某个特殊函数,或禁止某种类型的函数重载。
语法格式服下:
class 类名 {
public:
// 让编译器生成某个默认的特殊成员函数
特殊成员函数名() = default;
// 让编译器删除特殊成员函数。
特殊成员函数名() = delete;
// 删除对 double 类型的函数的重载。
返回类型 普通成员函数名(实参列表) = delete;
};
5.1 =default 显式默认函数
=default 关键字用于显式生成默认的特殊成员函数。
C++11 的类内有六个特殊成员函数,这六个函数的功能如下:
- 无参的构造函数:默认不执行任何操作,如果重载其构造函数则此无参的构造函数将丢失(不生成此成员函数)。
- 拷贝构造函数:默认成员变量之间依次赋值(浅拷贝)。
- 拷贝赋值函数:默认成员变量之间依次赋值(浅拷贝)。
- 析构函数:默认不执行任何操作。
- 移动构造函数:默认成员变量之间移动赋值。
- 移动赋值函数:默认成员变量之间移动赋值。
示例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:~$
以上程序语法正确,无报错。