命名空间
变体
操作

默认构造函数

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (在 C++17* 中弃用)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

默认构造函数是一个可以不带参数调用的 构造函数

目录

[编辑] 语法

类名(形参列表(可选)); (1)
类名(形参列表(可选)) 函数体 (2)
类名() = default; (3) (自 C++11 起)
类名(形参列表(可选)) = delete; (4) (自 C++11 起)
类名::类名(形参列表(可选)) 函数体 (5)
类名::类名() = default; (6) (自 C++11 起)
类名 - 正在声明其默认构造函数的类
形参列表 - 形参列表,其中所有形参(除了形参包(自 C++11 起)都有默认实参
函数体 - 默认构造函数的函数体

[编辑] 解释

1) 在类定义内部声明默认构造函数。
2-4) 在类定义内部定义默认构造函数。
3) 默认构造函数是显式预置的。
4) 默认构造函数被删除。
5,6) 在类定义外部定义默认构造函数(类必须包含声明 (1))。
6) 默认构造函数是显式预置的。

默认构造函数在默认初始化值初始化期间调用。

[编辑] 隐式声明的默认构造函数

如果类类型没有用户声明的构造函数或构造函数模板,编译器将隐式声明一个默认构造函数作为其类的 inline public 成员。

隐式声明(或在其首次声明时预置)的默认构造函数具有异常规范,如动态异常规范(直到 C++17) noexcept 规范(自 C++17 起)所述。

[编辑] 隐式定义的默认构造函数

如果构造函数是隐式声明的(直到 C++11)隐式声明或显式预置的默认构造函数未定义为已删除(自 C++11 起),则当 ODR 使用需要进行常量求值(自 C++11 起),它由编译器隐式定义。

如果类联合体 T 的默认构造函数是平凡的,那么对于每个作为 TT 的匿名联合体成员的联合体 U,如果 U 的第一个变体成员(如果有)具有隐式生存期类型,则 T 的默认构造函数会开始该成员的生存期(如果它不是其联合体的活动成员)。

(自 C++26 起)

一个(直到 C++26)否则,一个(自 C++26 起)隐式定义的默认构造函数具有与用户定义的带有空主体和空初始化器列表的构造函数相同的效果。也就是说,它调用此类的基类和非静态成员的默认构造函数。在值初始化期间,具有空的用户提供构造函数的类类型可能与具有隐式定义的默认构造函数的类类型得到不同的处理。

如果这满足constexpr 构造函数(直到 C++23)constexpr 函数(自 C++23 起)的要求,则生成的构造函数是 constexpr

如果存在一些用户定义的构造函数,用户仍然可以使用关键字 default 强制编译器自动生成默认构造函数,否则该构造函数将被隐式声明。

(自 C++11 起)


已删除的默认构造函数

如果满足以下任何条件,则类 T 的隐式声明或显式预置的默认构造函数被定义为已删除

  • T 具有没有默认初始化器的引用类型的非静态数据成员。
  • T是一个非联合体类,并且(自 C++26 起)具有常量限定类型(或可能是其多维数组)的非变体非静态非const-默认可构造数据成员,而没有默认成员初始化器。
  • T 是一个 联合体,并且其所有变体成员都是常量限定类型(或可能是其多维数组)。
  • T 是一个非联合体类,并且任何匿名联合体成员的所有成员都是常量限定类型(或可能是其多维数组)。
(直到 C++26)
  • 给定类类型 MT 具有类型为 M (或可能是其多维数组)的潜在构造的子对象 obj,并且满足以下任何条件
  • M 具有从默认构造函数删除或无法访问的析构函数,并且obj 是非变体,或者 obj 具有默认成员初始化器(自 C++26 起)
  • 满足以下所有条件
  • obj 不是具有默认初始化器的非静态数据成员。
  • obj 不是联合体的变体成员,其中另一个非静态数据成员具有默认初始化器(直到 C++26)
  • 应用于查找 M 的默认构造函数的重载解析不会产生可用的候选者,或者在 obj 是变体成员的情况下,选择一个非平凡函数(直到 C++26)

如果没有用户定义的构造函数并且隐式声明的默认构造函数不是平凡的,则用户仍然可以使用关键字 delete 来阻止编译器自动生成隐式定义的默认构造函数。

(自 C++11 起)

[编辑] 平凡默认构造函数

如果满足以下所有条件,则类 T 的默认构造函数是平凡的

  • 构造函数是隐式声明的(直到 C++11)不是用户提供的(自 C++11 起)
  • T 没有虚成员函数。
  • T 没有虚基类。
  • T 没有带有默认初始化器的非静态成员。
(自 C++11 起)
  • T 的每个直接基类都有一个平凡默认构造函数。
  • 类类型(或其数组)的每个非静态成员都有一个平凡默认构造函数。
(直到 C++26)
  • T 是一个联合体,或者类类型(或其数组)的每个非变体非静态成员都有一个平凡默认构造函数。
(自 C++26 起)

平凡默认构造函数是不执行任何操作的构造函数。与 C 语言兼容的所有数据类型(POD 类型)都是可平凡默认构造的。

[编辑] 合格默认构造函数

如果默认构造函数是用户声明的,或者既是隐式声明的又是可定义的,则它是合格的。

(直到 C++11)

如果默认构造函数未被删除,则它是合格的。

(自 C++11 起)
(直到 C++20)

如果满足以下所有条件,则默认构造函数是合格的

  • 它未被删除。
  • 它的关联约束(如果有)已满足。
  • 没有关联约束已满足的默认构造函数约束更多
(自 C++20 起)

合格默认构造函数的平凡性决定了该类是否为隐式生存期类型,以及该类是否为可平凡复制类型

[编辑] 注解

特性测试宏 Std 特性
__cpp_trivial_union 202502L (C++26) 放宽联合体的特殊成员函数的平凡性要求

[编辑] 示例

struct A
{
    int x;
    A(int x = 1): x(x) {} // user-defined default constructor
};
 
struct B : A
{
    // B::B() is implicitly-defined, calls A::A()
};
 
struct C
{
    A a;
    // C::C() is implicitly-defined, calls A::A()
};
 
struct D : A
{
    D(int y) : A(y) {}
    // D::D() is not declared because another constructor exists
};
 
struct E : A
{
    E(int y) : A(y) {}
    E() = default; // explicitly defaulted, calls A::A()
};
 
struct F
{
    int& ref; // reference member
    const int c; // const member
    // F::F() is implicitly defined as deleted
};
 
// user declared copy constructor (either user-provided, deleted or defaulted)
// prevents the implicit generation of a default constructor
 
struct G
{
    G(const G&) {}
    // G::G() is implicitly defined as deleted
};
 
struct H
{
    H(const H&) = delete;
    // H::H() is implicitly defined as deleted
};
 
struct I
{
    I(const I&) = default;
    // I::I() is implicitly defined as deleted
};
 
int main()
{
    A a;
    B b;
    C c;
//  D d; // compile error
    E e;
//  F f; // compile error
//  G g; // compile error
//  H h; // compile error
//  I i; // compile error
}

[编辑] 缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布行为 正确行为
CWG 1353 C++11 隐式声明的默认构造函数为
定义为已删除的条件没有考虑多维数组类型
考虑这些类型
CWG 2084 C++11 默认成员初始化器对是否
联合体的预置默认构造函数被删除没有影响
它们阻止预置默认
构造函数被删除
CWG 2595 C++20 如果存在
另一个约束更多的默认构造函数,则默认构造函数不合格
但不满足其关联约束
在这种情况下它可以是合格的
CWG 2871 C++98 即使存在用户声明的构造函数模板,也会隐式声明默认构造函数
即使存在用户声明的构造函数模板,也会隐式声明默认构造函数
无隐式声明
在这种情况下

[编辑] 参见