“多级继承的情况下的虚拟基类”是否具有重要意义

时间:2012-07-11 04:53:40

标签: c++ inheritance virtual virtual-inheritance

请考虑以下显示多级继承的示例代码:

案例1:此处,类derived1通过虚拟继承从类base派生,类derived2直接从类derived1派生。 /强>

class base
{

};

class derived1 : virtual public base
{

};

class derived2 : public derived1
{

};

案例2:与案例1相同,但不涉及虚拟继承

class base
{

};

class derived1 : public base // no virtual inheritance
{

};

class derived2 : public derived1
{

};

假设我在两种情况下都创建了类derived2的对象。

  1. Case1和Case2如何在derived2对象中包含子对象方面有所不同?

  2. Case1对Case2有意义吗?

  3. PS:我很清楚多重继承过程中虚拟基类的重要性。

4 个答案:

答案 0 :(得分:3)

在继承层次结构中没有基类的多个实例时,({1}}基类会考虑(至少)另外两个问题。

首先,虚拟基类始终由正在构建的派生类和非虚拟基类之前初始化。当中间类在其成员初始化列表中将参数传递给虚基类构造函数时,这一点最为明显。这些初始值设定项将被忽略。它也可以改变基类的构造顺序。

其次,无法从虚拟基类到继承自它的类执行virtual

答案 1 :(得分:2)

使用虚拟继承时存储了其他信息。这是为了允许动态强制转换在钻石情况下正确解析为派生类。 您的代码没有钻石情况,因此不使用该信息。

如果将数据成员添加到基类,则可以使附加信息可见:

class base {
protected:
    int i;
};

如果您现在在两种情况下打印每个派生类的大小,您会发现它们的大小从一个案例到另一个案例有所不同。

编辑:Charles Bailey对使用虚拟继承的语义差异提出了很好的观点。他的第一点特别有趣,应该给予更多考虑。他的观点基本上是derived2具有隐式菱形拓扑。也就是说,假设derived1实际上继承自base

class base {};
class derived1 : virtual public base {};

然后,derived2这三个版本之间没有区别,它们的行为与第一个版本相同:

class derived2 : virtual public base, public derived1 {};
class derived2 : public derived1, virtual public base {};
class derived2 : public derived1 {}

这意味着当您从类似derived1的类派生时(即使用虚拟继承的类)创建了一个隐式菱形。

    base
     |  \
     |   \.(virtual)
     |   / \
     |  /___\
     |    |
     | derived1
     |   /
     |  /
     |./
     / \ 
    /___\
      |
   derived2 

为了进一步说明这一点,derived1使用虚拟继承时允许这样做:

class derived2 : public derived1 {
public:
    derived2 () : base() {}
};

但是,如果derived1不使用虚拟继承,则不允许使用。

答案 2 :(得分:1)

虚拟继承在您的情况下没有意义 它仅为钻石继承缩进,如:

B: A
C: A
D: B, C

在这种情况下,两种情况下A的继承都应该是虚拟的。

答案 3 :(得分:1)

只有当类作为基类包含多次时,虚拟继承才会变得很重要。事实上,说明符virtual在这里意味着“只包含一次”。

如果没有多重继承,则不能多次指定同一个类(循环继承是一个明确的语法错误)。然后谈到编译器中的优化是多么好。如果编译器是完美的,那么没有区别。实际上,您承担了编译器将向您的类添加与多重继承相关的内容的风险。使用该语言的某些功能的次数越少,编译器混淆的风险就越大。编译器通常是一个高质量的程序,但这只是一个程序。