文章参考:
1. 类与默认函数
在C++中声明自定义的类,编译器会默认帮程序员生成一些未定义的成员函数,这些函数被称为默认函数
,一共有六个:
- 无参构造函数:创建类对象
- 拷贝构造函数:拷贝类对象
- 移动构造函数:拷贝类对象。
- 拷贝赋值函数:类对象赋值。
- 移动赋值函数:类对象赋值。
- 析构函数:销毁类对象。
而一旦程序员自定义了这些函数,则编译器不会为该类函数生成默认版本。这会为我们带来一些问题,其中一个就是:
- 一旦声明了自定义版本的构造函数,则就导致我们的类/结构体不再是
平凡(trivial)
的,也就不是POD
类型。
这会让我们失去POD
的一些优势。为了解决这一问题,C++11为我们提供了方法,那就是使用=default
关键字。
2. default
C++11中可以使用=default
来修饰函数,这样的函数被称为显式默认函数
。可以在类内部修饰,也可以在类外部修饰。
2.1 在类内部指定函数为默认函数
一般情况下,我们在定义类的时候直接在类内部指定默认函数:
class Base
{
public:
Base() = default;
// Base(int i) = default; error:default只能作用于六个默认形式的函数
Base(const Base& obj) = default;
Base(Base&& obj) = default;
Base& operator= (const Base& obj) = default;
Base& operator= (Base&& obj) = default;
~Base() = default;
};
其中:
- 第4行:指定无参构造函数为默认函数。
- 第6行:指定拷贝构造函数为默认函数。
- 第7行:指定移动构造函数为默认函数。
- 第8行:指定拷贝赋值操作符重载函数为默认函数。
- 第9行:指定移动赋值操作符重载函数为默认函数。
- 第10行:指定析构函数为默认函数。
2.2 在类外部指定函数为默认函数
// 类定义
class Base
{
public:
Base();
Base(const Base& obj);
Base(Base&& obj);
Base& operator= (const Base& obj);
Base& operator= (Base&& obj);
~Base();
};
// 在类定义之外指定成员函数为默认函数
Base::Base() = default;
Base::Base(const Base& obj) = default;
Base::Base(Base&& obj) = default;
Base& Base::operator= (const Base& obj) = default;
Base& Base::operator= (Base&& obj) = default;
Base::~Base() = default;
2.3 应用范围
只能用来修饰用户声明的、和上述六个默认函数形式一致
(指的是返回值类型、函数名、参数列表完全一致)的函数。 其他的都不行
class Base
{
public:
Base() = default;
// Base(int i=0) = default; error
// Base(int i, doublue j) = default; error
Base(const Base& obj) = default;
Base(Base&& obj) = default;
Base& operator= (const Base& obj) = default;
Base& operator= (Base&& obj) = default;
// bool operator== (const Base& obj) = default; error
~Base() = default;
};
3. delete
有时我们可能想要显式的禁止一些成员函数的实现,例如禁止用户使用默认生成函数。这样可以有效的防止某些类型之间自动进行隐式类型转换而产生错误。
3.1 禁止使用默认生成的函数
class Base
{
public:
Base() = default;
Base(const Base& obj) = delete;
Base& operator= (Base& obj) = delete;
};
int main()
{
Base b;
Base b1(b); // error
Base b2 = b; // error
Base b3;
b3 = b; // error
return 0;
}
- 第5行:仅用了拷贝构造函数。
- 第11、12行:由于拷贝构造函数被显式删除,无法拷贝对象。
- 第15行:由于移动赋值操作符重载函数已经被显式删除,无法对象。
3.2 禁止使用自定义函数
class Base{
private:
int _num;
public:
Base(int num): _num(num){}
Base(char c) = delete;
};
int main(void){
Base b1(1);
// Base b2('a'); error
return 0;
}
- 第6行:禁用带
char
类型参数的构造器。 - 第11行:因此带
char
类型参数的构造器被显式禁用了,因此这一句是错误的。