我想知道什么是“虚拟基类”以及它的含义。

让我举个例子:

class Foo
{
public:
    void DoSomething() { /* ... */ }
};

class Bar : public virtual Foo
{
public:
    void DoSpecific() { /* ... */ }
};

当前回答

除了前面提到的多重继承和虚拟继承之外,在Dr Dobb's Journal上还有一篇非常有趣的文章:多重继承被认为是有用的

其他回答

解释使用虚拟基的多重继承需要c++对象模型的知识。最好是在一篇文章中,而不是在评论框中,清楚地解释这个主题。

我发现最好的、易读的解释是这篇文章,它解决了我对这个问题的所有疑问:http://www.phpcompiler.org/articles/virtualinheritance.html

在读完这篇文章之后,你真的不需要再阅读关于这个主题的任何其他内容了(除非你是编译器作者)…

这意味着对虚函数的调用将被转发到“正确的”类。

C+ FAQ上升。

简而言之,它通常用于多继承场景,其中形成了“菱形”层次结构。虚继承将打破在底层类中创建的模糊性,当您调用该类中的函数并且函数需要解析到底层类之上的类D1或D2时。有关图表和详细信息,请参阅FAQ项。

它还用于姐妹委托,这是一个强大的功能(尽管不适合心脏薄弱的人)。请看这个FAQ。

参见Effective c++第3版中的第40项(第2版中的43项)。

虚拟基类用于虚拟继承,是一种使用多重继承时防止在继承层次结构中出现给定类的多个“实例”的方法。

考虑以下场景:

class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};

上面的类层次结构导致了“可怕的钻石”,看起来像这样:

  A
 / \
B   C
 \ /
  D

D的一个实例将由B和C组成,B包含A, C也包含A。所以你有两个A的“实例”(为了更好的表达)。

在这种情况下,就有可能出现模棱两可的情况。当你这样做时会发生什么:

D d;
d.Foo(); // is this B's Foo() or C's Foo() ??

虚拟继承可以解决这个问题。当您在继承类时指定virtual时,您是在告诉编译器您只需要一个实例。

class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};

这意味着在层次结构中只包含A的一个“实例”。因此

D d;
d.Foo(); // no longer ambiguous

这是一个小总结。要了解更多信息,请阅读这个和这个。这里还有一个很好的例子。

我想对OJ的善意澄清补充一点。

虚拟继承是有代价的。就像所有虚拟的东西一样,你的性能会受到影响。有一种方法可以绕过这种性能冲击,但可能不那么优雅。

你可以在菱形中添加另一层,而不是通过虚拟派生来打破菱形,以得到如下内容:

   B
  / \
D11 D12
 |   |
D21 D22
 \   /
  DD

没有一个类是虚继承的,所有类都是公开继承的。类D21和D22将隐藏虚函数f(),这对于DD来说是模糊的,可能是通过将函数声明为private。它们将分别定义一个包装器函数f1()和f2(),分别调用class-local (private) f(),从而解决冲突。类DD在需要D11::f()时调用f1(),在需要D12::f()时调用f2()。如果内联定义包装器,可能会得到零开销。

当然,如果您可以更改D11和D12,那么您可以在这些类中执行相同的技巧,但通常情况下并非如此。

虚基类是这样的类 不能被实例化:你不能 从它创建直接对象。

我认为你混淆了两件完全不同的事情。虚拟继承与抽象类不是一回事。虚继承修改函数调用的行为;有时它会解析否则会有歧义的函数调用,有时它将函数调用处理推迟到非虚继承中期望的类。