成员初始化列表必须写在构造函数参数括号之后、函数体之前,以冒号引导、逗号分隔,直接调用成员构造函数完成初始化;它不可用于赋值,对const成员、引用成员及无默认构造函数的类类型成员是唯一合法方式,且初始化顺序严格按类中声明顺序而非列表顺序执行。

成员初始化列表的基本写法
成员初始化列表写在构造函数参数括号之后、函数体之前,用冒号 : 引导,多个成员用逗号分隔。它不是赋值,而是直接调用成员的构造函数完成初始化。
常见错误是把它和函数体内赋值混淆,比如写成 this->x = x; —— 这对 const 成员、引用成员、没有默认构造函数的类类型成员根本编译不过。
-
class A { const int c; A() : c(42) {} };✅ 必须用初始化列表 -
class B { std::string s; B() : s("hello") {} };✅ 比s = "hello";更高效(避免默认构造 + 赋值) -
class C { int x, y; C() : x(1), y(x+1) {} };✅ 成员按声明顺序初始化,不是按列表顺序
初始化顺序和声明顺序不一致会出什么问题
初始化列表中成员的书写顺序不影响实际初始化顺序,C++ 严格按类中成员变量的**声明顺序**执行初始化。如果依赖未初始化的成员,就会读取垃圾值。
例如:class D { int a; int b; D() : b(a+1), a(5) {} }; 中,a 先被初始化(声明在前),但 b 的初始化表达式 a+1 却在 a 初始化前求值 —— 这是未定义行为。
- 编译器通常不报错,但运行时
b可能是任意值 - Clang 和 GCC 加
-Wreorder可警告(默认不开启) - 安全做法:让初始化列表顺序与声明顺序一致,并避免在初始化表达式中引用后声明的成员
哪些成员必须/建议用初始化列表
以下三类成员无法(或不应)在构造函数体内赋值,必须用初始化列表:
-
const成员:如const double PI;→ 必须: PI(3.14159) - 引用成员:如
int& ref;→ 必须绑定到有效对象,只能在初始化时做 - 没有默认构造函数的类类型成员:如
std::vector<int> v;</int>有默认构造函数,但自定义类Widget w;若只提供Widget(int),就必须: w(42)
即使不是强制要求,对内置类型(int、double)或有默认构造函数的类,也建议用初始化列表——避免冗余的默认构造 + 赋值两步操作。
初始化列表里调用成员函数或 this 指针安全吗
不安全。在初始化列表中,对象尚未构造完成,this 指向的是一个“半成品”对象,此时调用非静态成员函数属于未定义行为。
例如:class E { int x; E() : x(calc()) {} int calc() { return this->x * 2; } }; 中,calc() 访问了未初始化的 x,且 this 在此时不可靠。
- 可以调用
static成员函数(不依赖对象状态) - 可以调用全局函数或命名空间函数
- 绝对不要在初始化列表中调用虚函数(会调用基类版本,且行为不可靠)
复杂初始化逻辑应移到私有辅助函数中,但该函数必须只依赖参数或静态数据,不能访问 this 的其他成员。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











