成员变量初始化在构造函数体执行前完成,严格按声明顺序进行,与初始化列表顺序无关;const成员、引用成员及无默认构造函数的成员必须用初始化列表初始化。

成员变量的初始化不发生在构造函数体内,而是在进入构造函数体之前完成。实际顺序由语言规则硬性规定,与你写的代码顺序无关。
初始化发生的三个阶段
对象构造时,初始化严格按以下顺序推进:
- 所有直接基类(按继承声明顺序)先完成构造
- 类内非静态成员变量,按它们在类中声明的物理顺序依次初始化
- 最后才执行派生类构造函数体内的语句(即大括号 {} 中的内容)
成员变量之间谁先谁后,只看声明位置
哪怕你在初始化列表里写成 : b(42), a(b + 1),只要 a 在类定义中声明在 b 前面,a 就一定先初始化——此时 b 还未构造,b + 1 使用的是未定义值。
这种依赖关系出错不会编译失败,但会导致未定义行为。Clang 和 GCC 在 -Wall 下会警告 “field is initialized after field”,这个警告值得重视。
哪些成员必须走初始化列表
以下三类成员无法等到构造函数体内再处理,必须出现在初始化列表中:
- const 成员:对象诞生那一刻就必须绑定确定值,之后不可修改
- 引用成员(T&):引用必须初始化,且不能重新绑定
- 没有默认构造函数的自定义类型成员:无法默认构造,只能靠初始化列表传参调用其有参构造
基类、成员、函数体之间的顺序不可颠倒
这个顺序是 C++ 标准强制要求的,所有编译器一致:
- 虚基类 → 非虚基类(按继承顺序)
- → 类内成员(严格按声明顺序)
- → 构造函数体执行
例如:struct D : B1, B2 { int m1; string m2; D() : m2("x"), m1(42) { },输出一定是 B1 B2(基类),然后 m1(先声明),再 m2(后声明),最后才是构造函数体内容。











