为何C++类构造函数使用初始化列表而非函数体内赋值?
为什么C++构造函数里要用成员初始化列表而非函数体内赋值?
你提到的第一种写法叫做成员初始化列表,它和函数体内赋值的核心区别在于执行时机与底层逻辑,下面给你拆解清楚:
1. 效率差异(针对非内置类型)
对于std::string这类类类型成员:
- 用初始化列表
m_Name(name):直接调用std::string的拷贝构造函数,一步到位用name的值初始化m_Name,没有多余操作。 - 在函数体内赋值
m_Name = name:会先调用std::string的默认构造函数创建空字符串,再调用赋值运算符把name的值赋给它,多了一次默认构造的开销。虽然std::string的默认构造开销不大,但对更复杂的自定义类,这个效率差异会很明显。
2. 某些场景下必须用初始化列表
有几种情况,你根本没法用函数体内赋值,只能依赖初始化列表:
- 成员被
const修饰:比如const std::string m_Name,const对象必须在创建时初始化,不能后续赋值。 - 成员是引用类型:比如
std::string& m_Name,引用必须在声明时绑定对象,不能先默认创建再赋值。 - 成员类没有默认构造函数:如果你的成员是某个自定义类,且该类只提供带参数的构造函数,那必须用初始化列表传参构造它。
- 基类没有默认构造函数:比如
Player继承的Entity如果只有带参数的构造函数,Player的构造函数必须用初始化列表给Entity传参,否则编译报错。
3. 代码风格与一致性
不管成员是内置类型(int、double)还是类类型,统一用初始化列表的话,代码风格更一致,也能避免遗漏某些必须初始化的成员(比如const、引用),减少潜在的编译错误。
两种写法的执行流程对比
初始化列表写法
Player(const std::string& name) : m_Name(name) {}
- 进入构造函数体之前,先初始化所有类成员:调用
m_Name的拷贝构造函数,用name完成初始化。 - 执行构造函数体(此处为空)。
函数体内赋值写法
Player(const std::string& name) { m_Name = name; }
- 进入构造函数体之前,先默认初始化所有类成员:调用
m_Name的默认构造函数,创建空字符串。 - 执行构造函数体,调用
m_Name的赋值运算符,把name的值赋给它。
内容的提问来源于stack exchange,提问作者dg141
相关产品推荐
相关产品推荐

