虚拟继承实际上如何工作?

NPS*_*NPS 1 c++ inheritance virtual-inheritance

我知道钻石问题,但问题是 - 当我谷歌"虚拟继承"时,结果提到钻石问题.我想知道它一般是如何工作的,它与正常继承有什么不同.

我知道当一个类(通常)继承自另一个类时,它只包含其所有成员(字段和方法,不考虑访问级别).其中一些可能会被新成员覆盖或隐藏,但他们仍然存在.继承还定义了层次结构中类之间的某些关系,这些关系会影响转换和多态.

现在虚拟继承有何不同?例如:

class A
{
    public:
    int a;
    int b;
    void fun(int x)
    {}
    void gun(int x)
    {}
};

class B : public A
{
    public:
    int a;
    int c;
    void fun(int x)
    {}
    void hun(int x)
    {}
};

class C : virtual public A
{
    public:
    int a;
    int c;
    void fun(int x)
    {}
    void hun(int x)
    {}
};
Run Code Online (Sandbox Code Playgroud)

B和之间有什么区别C?我的例子没有利用其他任何差异吗?标准说什么?另外,如果C++ 03和C++ 11之间存在差异,请提及它.

Mik*_*our 5

使用单一级别的继承,行为没有区别.

不同之处在于从多个基类继承时,这些基类本身具有公共基类:

struct A {};
struct B : virtual A {};
struct C : virtual A {};
struct D : B,C {};
Run Code Online (Sandbox Code Playgroud)

在这个例子中,使用虚拟继承,D只包含一个A子对象,它BC子对象共享; 这是"钻石"模式:

    A
   / \
   B C
   \ /
    D
Run Code Online (Sandbox Code Playgroud)

没有虚拟继承,它将包含两个A子对象,而不是"菱形":

   A A
   | |
   B C
   \ /
    D
Run Code Online (Sandbox Code Playgroud)

无论是否有多重继承,如果您有多个继承级别,仍然存在差异:虚拟基类必须由派生类最多的类初始化,而不是由其直接派生类初始化.这是为了避免在多重继承的情况下,歧义其中(在上面的例子中)都BC原本负责初始化共享A.