规避C++菱形继承问题时存在哪些疏漏?
问题分析与解决
错误根源:虚拟继承的构造规则
你遇到的问题核心是对虚拟继承下虚基类的初始化规则理解有误:
- 在C++虚拟继承中,只有最派生类(这里是D)有权初始化虚基类(A),中间派生类(B、C)的构造函数里对虚基类A的构造调用会被编译器直接忽略。
- 你的代码中,D的构造函数没有显式初始化A,所以编译器自动调用A的默认构造函数(
A()),把A的x设为5,这就是输出都是5的原因。 - 另外你预期输出6和7是不符合虚拟继承逻辑的:虚拟继承的目的就是让B和C共享同一个A实例,不可能存在两个独立的A对象分别被B和C初始化。
修正方案
如果需要指定A的x值,必须在最派生类D的构造函数初始化列表中显式调用A的带参构造函数。比如修改D的构造函数:
class D : public B, public C { protected: int x; public: // 显式初始化虚基类A,虚基类的构造调用建议放在初始化列表最前面 D() : A(8), x(35), B(11), C(21) { } int get() { return x; } void set(int i) { x = i; return *this; } };
此时d.B::A::get()和d.C::A::get()都会输出8,因为它们访问的是同一个A实例。
补充说明
每个类里的x都是各自独立的成员:A有一个x,B、C、D各自也有自己的x,它们名字相同但属于不同类域,通过::可以区分访问。虚拟继承只影响基类A的实例数量,不影响这些各自的x成员。
内容的提问来源于stack exchange,提问作者Patrick O'Brien
相关产品推荐
相关产品推荐

