c++基类对象和成员对象的初始化顺序
#include <iostream>
using namespace std;
class B1 // 基类B1,构造函数有参数
{
public:
B1(int i) { cout << "constructing B1 " << i << endl; }
};
class B2 // 基类B2,构造函数有参数
{
public:
B2(int j) { cout << "constructing B2 " << j << endl; }
};
class B3 // 基类B3,构造函数无参数
{
public:
B3() { cout << "constructing B3 *" << endl; }
};
class C : public B2, public B1, public B3
{
public: // 派生类的公有成员
C(int a, int b, int c, int d) : B1(a), memberB2(d), memberB1(c), B2(b) {}
private: // 派生类的私有对象成员
B1 memberB1;
B2 memberB2;
B3 memberB3;
};
void main()
{
C obj(1, 2, 3, 4);
}
这段代码中的构造函数部分:
C(int a, int b, int c, int d) : B1(a), memberB2(d), memberB1(c), B2(b) {}
这是C++的构造函数初始化列表(Constructor Initialization List)语法。
语法解释:
基本格式:
构造函数名(参数列表) : 成员1(初始值), 成员2(初始值), ... {}
在这个例子中:
C(int a, int b, int c, int d)
- 派生类C的构造函数,接收4个参数:
- 初始化列表开始标志B1(a)
- 用参数a
(值为1)调用基类B1的构造函数memberB2(d)
- 用参数d
(值为4)初始化成员对象memberB2memberB1(c)
- 用参数c
(值为3)初始化成员对象memberB1B2(b)
- 用参数b
(值为2)调用基类B2的构造函数{}
- 构造函数体(这里是空的)
实际执行顺序:
重要:虽然初始化列表中的顺序是 B1(a), memberB2(d), memberB1(c), B2(b)
,但实际的构造顺序遵循固定规则:
-
基类构造:按继承声明顺序
class C : public B2, public B1, public B3 // 声明顺序
- B2(2) 先构造
- B1(1) 后构造
- B3() 最后构造(无参构造函数,自动调用)
-
成员对象构造:按成员声明顺序
private: B1 memberB1; // 先声明 B2 memberB2; // 后声明 B3 memberB3; // 最后声明
- memberB1(3) 先构造
- memberB2(4) 后构造
- memberB3() 最后构造(默认构造)
完整的输出结果:
constructing B2 2
constructing B1 1
constructing B3 *
constructing B1 3
constructing B2 4
constructing B3 *
为什么使用初始化列表?
-
必须使用的情况:
- 基类没有默认构造函数
- 成员对象没有默认构造函数
- const成员变量
- 引用成员变量
-
性能优势:
- 直接初始化,避免先默认构造再赋值
- 更高效
这种设计确保了派生类能够正确地初始化其基类和成员对象。