C++
编译器支持
独立与宿主式
语言
标准库
标准库头文件
具名要求
特性测试宏 (C++20 起)
语言支持库
概念库 (C++20 起)
诊断库
内存管理库
元编程库 (C++11 起)
通用工具库
容器库
迭代器库
范围库 (C++20 起)
算法库
字符串库
文本处理库
数值库
日期和时间库
输入/输出库
文件系统库 (C++17 起)
并发支持库 (C++11 起)
执行控制库 (C++26 起)
技术规范
符号索引
外部库
[编辑] C++ 语言
通用主题
预处理器
注释
关键字
转义序列
流程控制
条件执行语句
if
switch
迭代语句(循环)
for
范围 for (C++11 起)
while
do-while
跳转语句
continue - break
goto - return
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (在 C++17* 中弃用)
noexcept 说明符 (C++11 起)
异常
throw 表达式
try 块
catch 处理程序
命名空间
命名空间声明
命名空间别名
类型
基本类型
枚举类型
函数类型
类/结构体类型
联合体类型
说明符
const/volatile
decltype (C++11 起)
auto (C++11 起)
constexpr (C++11 起)
consteval (C++20 起)
constinit (C++20 起)
存储期说明符
初始化
默认初始化
值初始化
零初始化
复制初始化
直接初始化
聚合初始化
列表初始化 (C++11 起)
常量初始化
引用初始化
表达式
值类别
求值顺序
运算符
运算符优先级
备选表示
字面量
布尔 - 整数 - 浮点
字符 - 字符串 - nullptr (C++11 起)
用户定义 (C++11 起)
实用工具
属性 (C++11 起)
类型
typedef 声明
类型别名声明 (C++11 起)
转型
隐式转换
static_cast
const_cast
显式转换
dynamic_cast
reinterpret_cast
内存分配
new 表达式
delete 表达式
类
类声明
构造函数
this 指针
访问说明符
friend 说明符
类特定的函数属性
虚函数
override 说明符 (C++11 起)
final 说明符 (C++11 起)
explicit (C++11 起)
static
特殊成员函数
默认构造函数
复制构造函数
移动构造函数 (C++11 起)
复制赋值
移动赋值 (C++11 起)
析构函数
模板
类模板
函数模板
模板特化
形参包 (C++11 起)
其他
内联汇编
C++ 的历史
[编辑] 类
通用
概述
class/struct 类型
union 类型
注入类名
类属性说明符 (C++26 起)
成员
数据成员
静态成员
this 指针
嵌套类
成员模板
位域
using 声明
成员函数
成员访问说明符
构造函数与成员初始化列表
默认成员初始化器 (C++11 起)
friend 说明符
explicit 说明符
转换构造函数
特殊成员函数
默认构造函数
复制构造函数
移动构造函数 (C++11 起)
复制赋值运算符
移动赋值运算符 (C++11 起)
析构函数
继承
基类和派生类
空基类优化 (EBO)
虚成员函数
纯虚函数和抽象类
override 说明符 (C++11 起)
final 说明符 (C++11 起)
[编辑]
构造函数 是使用特殊的声明符语法声明的非静态 成员函数,它们用于初始化其类类型的对象。
构造函数不能是协程。
(C++20 起)
构造函数不能具有显式对象形参。
(C++23 起)
内容
1 语法
2 成员初始化列表
3 解释
3.1 构造与析构期间的操作
3.2 委托构造函数
3.3 继承构造函数
3.4 初始化顺序
4 注解
5 示例
6 缺陷报告
7 引用
8 参见
[编辑] 语法
构造函数使用下列形式的成员函数声明符声明
类名 ( 形参列表(可选) ) except(可选) attr(可选)
类名
-
一个标识符表达式,可能后随属性列表,并且(C++11 起)可能被一对圆括号括起来
形参列表
-
形参列表
except
-
动态异常规范
(C++11 前)
或者动态异常规范或者noexcept 规范
(C++11 起)(C++17 前)
noexcept 规范
(C++17 起)
attr
-
(C++11 起) 属性列表
在构造函数声明的声明说明符中,唯一允许的说明符是 friend、 inline、 constexpr(C++11 起)、 consteval(C++20 起) 和 explicit (特别地,不允许返回类型)。注意 cv 限定符和引用限定符 也不被允许:构造中的对象的 const 和 volatile 语义只在最派生类的构造函数完成后才生效。
类名 的标识符表达式必须有下列形式之一
在 友元声明 中,标识符表达式是限定标识符,它命名一个构造函数。否则,在属于类或类模板的成员规范的成员声明中
对于类,标识符表达式是立即外围类的注入类名。对于类模板,标识符表达式是命名当前实例化的类名(C++20 前)立即外围类模板的注入类名(C++20 起)。
否则,标识符表达式是限定标识符,其终结的非限定标识符是其查找语境的注入类名。
[编辑] 成员初始化列表
任何构造函数的函数定义的函数体,在复合语句的左花括号之前,可以包含成员初始化列表,其语法是冒号字符 :,后随逗号分隔的一个或多个成员初始化器列表,每个初始化器有下列语法
类或标识符 ( 表达式列表(可选) )
(1)
类或标识符 花括号初始化列表
(2)
(C++11 起)
形参包 ...
(3)
(C++11 起)
1) 使用直接初始化,或者若 表达式列表 为空,则使用值初始化,来初始化由 类或标识符 命名的基类或成员
2) 使用列表初始化(若列表为空则变为值初始化,而初始化聚合体时则为聚合初始化)初始化由 类或标识符 命名的基类或成员
3) 使用包展开初始化多个基类
类或标识符
-
任何命名非静态数据成员的标识符,或任何命名类自身(对于委托构造函数)或直接或虚基类的类型名。
表达式列表
-
可能为空,逗号分隔的参数列表,用于传递给基类或成员的构造函数
花括号初始化列表
-
花括号包围的初始化器列表
形参包
-
可变参数模板形参包的名字
运行此代码
struct S
{
int n;
S(int); // constructor declaration
S() : n(7) {} // constructor definition:
// ": n(7)" is the initializer list
// ": n(7) {}" is the function body
};
S::S(int x) : n{x} {} // constructor definition: ": n{x}" is the initializer list
int main()
{
S s; // calls S::S()
S s2(10); // calls S::S(int)
}
[编辑] 解释
构造函数没有名字,不能直接调用。它们在初始化发生时被调用,并根据初始化的规则被选择。explicit 说明符的构造函数是转换构造函数。具有 constexpr 说明符的构造函数使其类型成为字面类型。可以不带任何实参调用的构造函数是默认构造函数。接受相同类型的另一个对象作为实参的构造函数是复制构造函数和移动构造函数。
在构成构造函数函数体的复合语句开始执行之前,所有直接基类、虚基类和非静态数据成员的初始化都已完成。成员初始化列表是可以指定这些子对象的非默认初始化的位置。对于不能默认初始化的基类,以及不能通过默认初始化或通过它们的默认成员初始化器(如果有)(C++11 起)来初始化的非静态数据成员,例如引用和 const 限定类型的成员,必须指定成员初始化器。(注意,如果成员类型或初始化器是依赖型的,则类模板实例化的非静态数据成员的默认成员初始化器可能无效。)(C++11 起)不为匿名联合体或没有成员初始化器或默认成员初始化器(C++11 起)的变体成员执行初始化。
当 类或标识符 命名虚基类时,初始化器在构造任何不是正被构造对象的最终派生类的类期间被忽略。
出现在 表达式列表 或 花括号初始化列表 中的名字在构造函数的作用域中求值
class X
{
int a, b, i, j;
public:
const int& r;
X(int i)
: r(a) // initializes X::r to refer to X::a
, b{i} // initializes X::b to the value of the parameter i
, i(i) // initializes X::i to the value of the parameter i
, j(this->i) // initializes X::j to the value of X::i
{}
};
从成员初始化器抛出的异常可以被函数 try 块处理。
如果非静态数据成员具有默认成员初始化器,并且也出现在成员初始化列表,则使用成员初始化器,并忽略默认成员初始化器
struct S
{
int n = 42; // default member initializer
S() : n(7) {} // will set n to 7, not 42
};
(C++11 起)
引用成员不能在成员初始化列表中绑定到临时量
struct A
{
A() : v(42) {} // Error
const int& v;
};
注意:这同样适用于默认成员初始化器。
[编辑] 构造与析构期间的操作
成员函数(包含虚成员函数)可以为正在构造或析构的对象调用。类似地,正在构造或析构的对象可以是 typeid 或 dynamic_cast 的操作数。
但是,如果在下列求值的任何一个期间执行这些操作,则行为是未定义的
构造函数的前置条件断言的求值析构函数的后置条件断言的求值
(C++26 起)
在所有基类的 成员初始化器 完成之前,成员初始化列表的求值
委托构造函数
如果类自身的名字作为 类或标识符 出现在成员初始化列表中,则该列表必须仅由一个成员初始化器组成;这样的构造函数被称为委托构造函数,而由初始化列表中唯一的成员选择的构造函数是目标构造函数。
在这种情况下,目标构造函数通过重载决议选择并首先执行,然后控制返回到委托构造函数并执行其函数体。
委托构造函数不能是递归的。
class Foo
{
public:
Foo(char x, int y) {}
Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char, int)
};
继承构造函数
参见 using 声明。
(C++11 起)
[编辑] 初始化顺序
成员初始化器在列表中的顺序无关紧要:实际的初始化顺序如下
1) 如果构造函数用于最终派生类,则虚基类按照它们在基类声明的深度优先、从左到右遍历中出现的顺序初始化(从左到右指的是在基类指定符列表中出现)。
2) 然后,直接基类按照它们在此类的基类指定符列表中出现的从左到右的顺序初始化。
3) 然后,非静态数据成员按照它们在类定义中声明的顺序初始化。
4) 最后,执行构造函数的函数体。
(注意:如果初始化顺序由不同构造函数的成员初始化列表中的出现顺序控制,那么析构函数将无法确保析构顺序与构造顺序相反。)
[编辑] 注解
特性测试宏
值
Std
特性
__cpp_delegating_constructors
200604L
(C++11)
委托构造函数
[编辑] 示例
运行此代码
#include
#include
#include
struct Base
{
int n;
};
struct Class : public Base
{
unsigned char x;
unsigned char y;
std::mutex m;
std::lock_guard
std::fstream f;
std::string s;
Class(int x) : Base{123}, // initialize base class
x(x), // x (member) is initialized with x (parameter)
y{0}, // y initialized to 0
f{"test.cc", std::ios::app}, // this takes place after m and lg are initialized
s(__func__), // __func__ is available because init-list is a part of constructor
lg(m), // lg uses m, which is already initialized
m{} // m is initialized before lg even though it appears last here
{} // empty compound statement
Class(double a) : y(a + 1),
x(y), // x will be initialized before y, its value here is indeterminate
lg(m)
{} // base class initializer does not appear in the list, it is
// default-initialized (not the same as if Base() were used, which is value-init)
Class()
try // function try block begins before the function body, which includes init list
: Class(0.0) // delegate constructor
{
// ...
}
catch (...)
{
// exception occurred on initialization
}
};
int main()
{
Class c;
Class c1(1);
Class c2(0.1);
}
[编辑] 缺陷报告
以下行为更改的缺陷报告被追溯应用于先前发布的 C++ 标准。
DR
应用于
已发布行为
正确行为
CWG 194
C++98
构造函数的声明符语法仅允许至多一个函数说明符(例如,构造函数不能声明为 inline explicit)
允许多个函数说明符
CWG 257
C++98
抽象类是否应为其虚基类提供成员初始化器是不明确的
指定为非必需并且在执行期间忽略此类成员初始化器
CWG 263
C++98
构造函数的声明符语法禁止构造函数为友元
允许构造函数为友元
CWG 1345
C++98
没有默认成员初始化器的匿名联合体成员被默认初始化
它们未被初始化
CWG 1435
C++98
“类名”在构造函数的声明符语法中的含义不明确
将语法更改为专门的函数声明符语法
CWG 1696
C++98
引用成员可以初始化为临时量(其生命周期将在构造函数结束时结束)
此类初始化是非良构的
[编辑] 引用
C++23 标准 (ISO/IEC 14882:2024)
11.4.5 构造函数 [class.ctor]
11.9.3 初始化基类和成员 [class.base.init]
C++20 标准 (ISO/IEC 14882:2020)
11.4.4 构造函数 [class.ctor]
11.10.2 初始化基类和成员 [class.base.init]
C++17 标准 (ISO/IEC 14882:2017)
15.1 构造函数 [class.ctor]
15.6.2 初始化基类和成员 [class.base.init]
C++14 标准 (ISO/IEC 14882:2014)
12.1 构造函数 [class.ctor]
12.6.2 初始化基类和成员 [class.base.init]
C++11 标准 (ISO/IEC 14882:2011)
12.1 构造函数 [class.ctor]
12.6.2 初始化基类和成员 [class.base.init]
C++98 标准 (ISO/IEC 14882:1998)
12.1 构造函数 [class.ctor]
12.6.2 初始化基类和成员 [class.base.init]
[编辑] 参见
复制消除
转换构造函数
复制赋值
复制构造函数
默认构造函数
析构函数
explicit
初始化
聚合初始化
常量初始化
复制初始化
默认初始化
直接初始化
列表初始化
引用初始化
值初始化
零初始化
移动赋值
移动构造函数
new