命名空间
变体
操作

默认构造函数

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
 
 

默认构造函数是无需任何实参即可调用的构造函数

目录

[编辑] 语法

类名 (参数列表 (可选)); (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`的默认构造函数是平凡的,那么对于每个联合`U`,如果`U`是`T`或`T`的匿名联合成员,如果`U`的第一个变体成员(如果有)具有隐式生命周期类型,则`T`的默认构造函数将开始该成员的生命周期,如果它不是其联合的活跃成员。

(C++26 起)

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

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

如果存在一些用户定义的构造函数,用户仍然可以通过关键字default强制编译器自动生成原本会隐式声明的默认构造函数。

(C++11 起)


已删除的默认构造函数

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

  • `T`有一个没有默认初始化器的引用类型的非静态数据成员。
  • `T`是一个非联合类,并且(C++26 起)有一个非变体非静态非const-默认可构造的const-qualified类型(或其可能的多维数组)数据成员,且没有默认成员初始化器。
  • `T`是一个联合,并且其所有变体成员都是const-qualified类型(或其可能的多维数组)。
  • `T`是一个非联合类,并且任何匿名联合成员的所有成员都是const-qualified类型(或其可能的多维数组)。
(直到 C++26)
  • 给定类类型`M`,`T`具有类型`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 起)

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

[编辑] 注释

功能测试宏 标准 特性
__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++ 标准。

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

[编辑] 另请参阅