为什么必须由最派生的类构建虚拟基类

Why must virtual base classes be constructed by the most derived class?

本文关键字:构建 虚拟 基类 派生 为什么      更新时间:2023-10-16

以下代码不会编译:

class A {
public:
    A(int) {}
};
class B: virtual public A {
public:
    B(): A(0) {}
};
// most derived class
class C: public B {
public:
    C() {} // wrong!!!
};

如果我在C的构造函数初始化列表中调用A的构造函数,那就是:

// most derived class
class C: public B {
public:
    C(): A(0) {} // OK!!!
};

它确实有效。

显然,原因是因为虚拟基类必须始终由最派生的类构建

我不明白此限制背后的原因。

,因为它避免了这种情况:

class A {
public:
    A(int) {}
};
class B0: virtual public A {
public:
    B0(): A(0) {}
};
class B1: virtual public A {
public:
    B1(): A(1) {}
};
class C: public B0, public B1 {
public:
    C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};

,因为在类层次结构中具有几乎继承的基类,因此可以/可以通过多个类共享基类(例如,在钻石继承中,同一基类是由多个多个基础继承的课程(。这意味着,实际上只有一个基本类别的副本。从本质上讲,这意味着基类必须首先构建。最终意味着派生类必须实例化给定的基类。

例如:

class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.

我发现此规则容易出错且笨拙(但是,多个继承的哪一部分不是?(。

但是逻辑上施加的构造顺序必须与正常(非虚拟(继承的情况不同。考虑Ajay的示例,减去虚拟:

class A;
class B1 : A;
class B2 : A;
class C: B1,B2

在这种情况下,对于每个C两个,一个作为B1的一部分,另一个是B2的一部分。B类的代码是为此负责的,并且可以做到。事件的顺序是:

Start C ctor
   Start B1 ctor
      A ctor (in B's ctor code)
   End B1 ctor
   Start B2 ctor
      A ctor (in B's ctor code)
   End B2 ctor
End C ctor

现在考虑

中的虚拟继承
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 

事件的一个顺序是

Start C ctor
   A ctor // not B's code!
   Start B1 ctor
      // NO A ctor
   End B1 ctor
   Start B2 ctor
      // NO A ctor
   End B2 ctor
End C ctor

重要的逻辑区别在于,A型A类型AS 的几乎继承的基类子对象是最派生的类的一部分,并且在其控制下(此处 C(。

B的构造函数一无所知,无法访问A。因此,他们无法构造A的子对象,包括基类。