构造函数初始化列表在冒号后、函数体前用逗号分隔,直接调用成员构造函数初始化;必须用于const成员、引用成员及无默认构造函数的类类型成员,且初始化顺序按声明顺序而非列表顺序。
构造函数初始化列表的基本写法
构造函数初始化列表在
之后、函数体
之前书写,用逗号分隔每个成员的初始化表达式。它不是赋值,而是直接调用成员的构造函数完成初始化。
常见错误是把初始化列表写成赋值语句,比如写成
—— 这对内置类型看似可行,但对自定义类型(如
、引用、const 成员)会编译失败或引发未定义行为。
顺序按类中成员声明顺序执行,与初始化列表中书写顺序无关
必须用初始化列表初始化:引用成员、
成员、没有默认构造函数的类类型成员
哪些成员必须放在初始化列表里
以下三类成员无法在构造函数体内赋值,只能靠初始化列表:
成员:一旦声明就不可修改,例如
引用成员:引用必须绑定到有效对象,且不能重新绑定,例如
没有默认构造函数的类类型成员:比如
默认可构造,但若你定义了
,那么
就不合法,必须写成
在初始化列表中
漏掉这些会导致
编译错误
,典型提示如:
。
立即学习
“
C++免费学习笔记(深入)
”;
C函数速查手册(CHM版)
C函数速查手册(CHM版)
下载
初始化列表 vs 构造函数体内赋值的区别
区别本质在于:初始化列表调用的是成员的构造函数;而函数体内赋值调用的是赋值运算符(
),前提是该成员已隐式构造完成。
对
:初始化列表
直接调用
;函数体内
先调默认构造函数,再调赋值,多一次开销
对自定义类,若其默认构造函数有副作用(如日志、资源申请),而你本意只想初始化为某个状态,那体内赋值等于“先做无用动作,再覆盖”,逻辑冗余甚至出错
内置类型(
、
)两者性能无差别,但统一用初始化列表更一致、更安全
容易被忽略的细节和坑
初始化顺序只取决于成员在类中声明的顺序,而不是初始化列表里的顺序。这点极易被忽视,导致未定义行为。
例如:
—— 尽管
写在前面,但
先声明,所以先初始化
,此时
还未构造,
会得到垃圾值
基类构造必须出现在派生类初始化列表最前面(隐式或显式),否则编译报错
初始化列表中不能调用虚函数(因为此时虚表尚未完全设置好),即使语法允许,行为也是静态绑定
初始化列表中不能使用
指针(对象尚未完全构造)
实际写代码时,建议把初始化列表写得和成员声明顺序严格一致,减少认知负担和潜在 bug。
:{}MyClass() { a = 1; b = "hello"; }std::stringclass A { int x; std::string s; const int c; public: A() : x(0), s("default"), c(42) {} };constconstconst int id;int& ref;std::vector v; class B { B(int); };B b;B b(5);member 'xxx' must be initialized by a mem-initializer in the constructoroperator=std::string s;s("abc")string(const char*)s = "abc";intdoubleclass X { int a; int b; X() : b(0), a(b) {} };baabathis