成员初始化列表是C++中高效安全初始化成员的唯一机制,必须用冒号语法,按声明顺序初始化const、引用及无默认构造函数的成员,避免赋值开销与未定义行为。

用成员初始化列表一次性搞定所有成员
直接在构造函数声明后加冒号,后面跟上每个成员的初始化表达式。这是最高效、最安全的方式,尤其对 const 成员、引用成员、无默认构造函数的类类型成员必不可少。
常见错误是误用赋值语句(=)代替初始化:这会导致先调用默认构造函数,再调用赋值运算符,多一次开销,甚至对某些类型(如 const int)根本编译不过。
class A { int x; std::string s; const double pi; A() : x(42), s("hello"), pi(3.14159) {} };- 初始化顺序严格按成员在类中声明的顺序,不是按初始化列表里的书写顺序
- 如果某个成员依赖另一个成员的值(比如
s用x构造),必须确保x在s之前声明,否则行为未定义
用委托构造函数避免重复初始化逻辑
当多个构造函数要做相似的初始化工作时,把公共部分抽到一个私有构造函数里,其他构造函数通过 : A(args...) {} 委托它执行。这样既复用代码,又保持所有成员只被初始化一次。
注意委托构造函数不能同时在初始化列表里初始化其他成员——整个初始化过程由被委托的构造函数全权负责。
立即学习“C++免费学习笔记(深入)”;
- 被委托的构造函数必须是第一个被执行的(即冒号后紧跟
A(...)) - 不能在委托之后再写其他初始化项,否则编译报错:
error: constructor delegation not allowed after member initialization - 例如:
A(int v) : A(v, "default") {}→ 调用A(int, std::string)完成全部初始化
用内联初始化(C++11起)简化默认值设定
在类定义里直接给非静态数据成员赋默认值,比如 int count = 0; 或 std::vector<int> data{1, 2, 3};</int>。它会在进入任何构造函数体之前生效,且会被成员初始化列表中的显式值覆盖。
这种写法适合提供合理默认值,但不适用于需要根据参数动态计算的场景;若和初始化列表共存,后者优先级更高。
- 对内置类型(如
int)写= 0比留空更安全,避免未初始化值 - 对类类型成员,会调用其对应构造函数(如
std::string s = "init";等价于调用std::string("init")) - 不能用于
static成员(需在类外定义),也不能用于const引用(必须在初始化列表中绑定)
别踩这些坑:初始化 vs 赋值、顺序陷阱、聚合类型例外
最容易混淆的是把初始化当成赋值。比如在构造函数体内写 x = 42; 是赋值,不是初始化——此时 x 已经被默认构造过了(对内置类型是未定义值,对类类型是调用了默认构造)。
聚合类(无用户定义构造函数、无 private/protected 非静态成员等)可以用 {} 直接列表初始化,但这属于 aggregate initialization,不走构造函数路径,也不触发成员初始化列表。
- 成员初始化列表里调用的构造函数必须可访问(比如不能是
private) - 基类成员必须在派生类初始化列表最前面初始化(顺序仍是声明顺序,但基类声明总在派生类成员之前)
- 如果忘了初始化某个类类型成员,而它又没有默认构造函数,编译直接失败:
error: no matching function for call to 'SomeClass::SomeClass()'


















