1.35、成员变量初始化的顺序是什么?
成员变量初始化的顺序
- 1. 基类子对象先于派生类子对象初始化
- • 首先初始化虚基类(如果有),按照继承声明的顺序(深度优先、左到右)。
- • 接着初始化直接基类,顺序与类声明中基类列表的顺序一致。
- 2. 成员变量初始化顺序由成员声明顺序决定
- • 无论构造函数初始化列表中写的顺序如何,成员变量总是按照它们在类中声明的先后顺序依次初始化。
- • 这意味着即使你在初始化列表中调换了顺序,实际初始化顺序不会改变,编译器会按照声明顺序执行。
- 3. 构造函数体内的赋值操作发生在成员初始化之后
- • 如果成员没有在初始化列表中初始化,则会先调用默认构造函数(或进行默认初始化),然后在构造函数体内赋值。
- • 这通常效率较低,且对于const成员和引用成员,必须在初始化列表中初始化。
- 4. 特殊成员的初始化要求
- • const成员和引用成员必须在初始化列表中初始化,不能在构造函数体内赋值。
- • static成员变量不属于对象实例,不在构造函数中初始化,必须在类外定义并初始化。
典型顺序总结
阶段 | 初始化顺序说明 |
静态变量 | 全局静态变量和类的静态成员变量先于对象初始化 |
虚基类 | 按继承图深度优先、左到右顺序初始化 |
直接基类 | 按声明顺序初始化 |
非静态数据成员 | 按声明顺序初始化 |
构造函数体 | 执行构造函数体内的语句 |
额外建议
- • 初始化列表中成员顺序应与声明顺序一致,避免阅读误导和编译器警告。
- • 避免成员间初始化依赖,防止因顺序错误导致未定义行为。
- • 对于复杂依赖,考虑使用委托构造函数或工厂函数保证初始化安全。
参考示例
class Base {
public:
Base() { /*...*/ }
};
class Derived : public Base {
int a;
int b;
public:
Derived(int x, int y)
: b(y), a(x) // 虽然b先写,但a会先初始化,因为a先声明
{
// 构造函数体
}
};
在上例中,a
会先于b
初始化,因为它在类中先声明,初始化列表的顺序不会影响实际初始化顺序。
总结
成员变量初始化顺序由基类继承层次和成员声明顺序决定,与构造函数初始化列表顺序无关。理解这一点是编写健壮、无隐藏bug的C++类构造函数的基础。
(加入我的知识星球,免费获取账号,解锁所有文章。)
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/1294
文章版权归作者所有,未经允许请勿转载。
THE END