默认构造函数
< cpp | language
默认构造函数是能以无参数调用的构造函数(以空参数列表定义,或以为每个参数提供默认参数定义)。拥有公开默认构造函数的类型是可默认构造 (DefaultConstructible) 的。
语法
class_name ( ) ; | (1) | ||||||||
class_name :: class_name ( ) body | (2) | ||||||||
class_name() = delete ; | (3) | (C++11 起) | |||||||
class_name() = default ; | (4) | (C++11 起) | |||||||
class_name :: class_name ( ) = default ; | (5) | (C++11 起) | |||||||
其中 class_name 必须指名当前类(或类模板的当前实例化),或在命名空间作用域或友元声明中声明时,必须是有限定类名。
解释
1) 默认构造函数的声明。
2) 默认构造函数的类体外定义。
3) 禁止编译器自动生成默认构造函数。
4) 显式强制编译器自动生成默认构造函数。
默认构造函数在默认初始化和值初始化时得到调用。
隐式声明的默认构造函数
若不对类类型(struct 、 class 或 union)提供任何用户声明的构造函数,则编译器将始终自动声明作为其类的 inline public
成员的默认构造函数。
若存在某个用户声明的构造函数,则用户仍可以关键词 | (C++11 起) |
隐式声明(或在其首声明设为默认)的默认构造函数拥有描述于动态异常规定 (C++17 前)异常规定 (C++17 起)的异常规定。
隐式定义的默认构造函数
若隐式声明的默认构造函数未被定义为被删除,则若得到odr 使用,则它为编译器所定义(即生成函数体并编译),且它与拥有空体和空初始化器列表的用户定义构造函数有准确相同的效果。即它调用基类和此类的非静态成员的默认构造函数。若它满足 constexpr 构造函数的要求,则生成的构造函数为 constexpr
。 (C++11 起)
若存在某个用户定义的构造函数,则用户仍可以关键词 | (C++11 起) |
被删除的隐式声明的默认构造函数
若下列任何一者为真,则类 T
式声明的或设为默认的默认构造函数不被定义 (C++11 前)定义为被删除 (C++11 起):
T
拥有无默认初始化器的 (C++11 起)引用类型成员。T
拥有无用户定义默认构造函数或默认成员初始化器 (C++11 起)的 const 成员。T
拥有默认构造函数被删除,或其默认构造函数有歧义或不可从此构造函数访问(无默认成员初始化器) (C++11 起)的成员。T
拥有默认构造函数被删除,或有歧义,或不可从此构造函数访问的直接基类或虚基类。T
拥有析构函数被删除,或不可从此构造函数访问的直接基类或虚基类。
| (C++11 起) |
T
为 union 且其所有变体成员均为 const 。
若不存在用户定义的构造函数,且隐式声明的默认构造函数非平凡,则用户仍可以关键词 | (C++11 起) |
平凡默认构造函数
若下列全部为真则类 T
的默认构造函数为平凡(即不进行动作):
- 构造函数非用户提供(即是隐式定义或为默认化)
T
无虚成员函数T
无虚基类
| (C++11 起) |
- 每个
T
的直接基类都拥有平凡默认构造函数 - 每个类类型的非静态成员都拥有平凡默认构造函数
平凡默认构造函数是不进行动作的构造函数。所有与 C 语言兼容的数据类型( POD 类型)都是可平凡默认构造的。然而不同于 C 中,拥有平凡默认构造函数的对象不能通过简单地转译对齐的存储,例如以 std::malloc 分配的存储创建:要求布置 new 以形式上引入新对象并避免潜在的未定义行为。
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
DR | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 2084 | C++11 | 默认成员初始化器不影响是否删除联合体的默认化默认构造函数 | 它们阻止定义默认化默认构造函数为被删除 |
示例
struct A
{
int x;
A(int x = 1): x(x) {} // 用户定义默认构造函数
};
struct B: A
{
// 隐式定义 B::B() ,调用 A::A()
};
struct C
{
A a;
// 隐式定义 C::C() ,调用 A::A()
};
struct D: A
{
D(int y): A(y) {}
// 不声明 D::D() ,因为存在另一构造函数
};
struct E: A
{
E(int y): A(y) {}
E() = default; // 显式为默认,调用 A::A()
};
struct F
{
int& ref; // 引用成员
const int c; // const 成员
// F::F() 被隐式定义为被删除
};
int main()
{
A a;
B b;
C c;
// D d; // 编译错误
E e;
// F f; // 编译错误
}