构造函数的成员初始化列表(initializer list)虽然语法可选,但有些情况下是必须使用的!下面我直接给你划重点,附带示例,保准你一目了然。
🧠 一、什么时候必须使用初始化列表?
以下这几种情况,只能用初始化列表,不能在构造函数体里赋值!
场景 | 必须用初始化列表的原因 |
---|---|
✅ const 成员变量 | 只能初始化,不能赋值 |
✅ 引用类型成员(T& ) | 引用必须在定义时初始化 |
✅ 没有默认构造函数的成员对象 | 不能先默认构造再赋值 |
✅ 基类构造需要参数 | 基类初始化只能写在列表中 |
✅ 多继承中虚基类构造 | 虚基类必须在最派生类初始化 |
📦 二、每种情况举例说明
✅ 1. const
成员变量
class A {
const int x;
public:
A(int val) : x(val) { } // ✅ 正确
// A(int val) { x = val; } // ❌ 错误:const 不能赋值
};
✅ 2. 引用成员(T&
)
class A {
int& ref;
public:
A(int& r) : ref(r) { } // ✅ 正确
// A(int& r) { ref = r; } // ❌ 错误:引用必须初始化
};
✅ 3. 成员对象没有默认构造函数
class B {
public:
B(int x) { /* ... */ }
};
class A {
B b;
public:
A() : b(42) { } // ✅ 正确
// A() { b = B(42); } // ❌ 错误:b 无默认构造函数,构造失败
};
✅ 4. 基类构造函数需要参数
class Base {
public:
Base(int x) { }
};
class Derived : public Base {
public:
Derived(int y) : Base(y) { } // ✅ 必须在初始化列表中指定
};
✅ 5. 虚基类的初始化(多继承)
class VBase {
public:
VBase(int x) { }
};
class A : virtual public VBase {
public:
A(int x) : VBase(x) { } // ✅ 虚基类只能在最派生类初始化
};
🚨 三、不是必须,但强烈推荐的情况
成员 | 建议 |
---|---|
普通成员变量 | 推荐用初始化列表,效率更高(避免“先构造默认值,再赋值”) |
STL 成员(如 std::string , std::vector ) | 直接用初始化列表传参构造,更高效 |
成员较多时 | 初始化列表写清楚,结构更清晰 |
🎯 总结一句话:
只要你遇到 const、引用、没有默认构造函数的成员、需要给基类传参 —— 统统必须用初始化列表!
📌 Bonus:初始化列表的执行顺序?
不按你写的顺序来!是按照成员声明的顺序初始化的!
class A {
int x;
int y;
public:
A() : y(2), x(1) { } // 实际初始化顺序是:x → y
};
🧨 写错顺序不会错,但可能造成潜在 bug。编译器可能给你个 warning。