当 类 的多重继承本身在其层次结构中具有菱形继承时,功能继承不明确

Ambiguous inheritance of function when multiple inheritance of classes that themselves have diamond inheritance in their hierarchy

文字描述下面的代码):我有一个库,提供了classes的集合。对于每组 class,我们有两个具体类型,(ClassA_PartialClassA)、(ClassB_PartialClassB) 等。这些实现中的每一个 (Interface_Partial, Interface) 分别。此外,Interface 是一个 Interface_Partial,每个Class? 是一个 Class?_Partial - 创建钻石继承模式,顶部虚拟继承。

为什么在继承 ClassAClassB 时,Interface_Partial 函数不明确?

struct Interface_Partial
{ 
    virtual ~Interface_Partial(); 
    virtual void f() = 0;
};

struct Interface
    :
    virtual Interface_Partial
{
    virtual void g() = 0;
};


struct ClassA_Partial : public virtual Interface_Partial
{
    void f() {};
};


struct ClassA : public Interface, public virtual ClassA_Partial
{
    void g() {};
};

struct ClassB_Partial : public virtual Interface_Partial
{
    void f() {};
};


struct ClassB : public Interface, public virtual ClassB_Partial
{
    void g() {};
};

struct MyClass : public ClassA, public ClassB
{ }; // error C2250: MyClass : ambiguous inheritance of 'void Interface_Partial::f(void)'

当我们多次继承一个公共接口时,为什么我们不能像通常那样消除歧义?例如

struct ClassX : public Interface_Partial { void f() {} };
struct ClassY : public Interface_Partial { void f() {} };
class Another : public ClassX, public ClassY
{};

void func()
{
    // This is ok
    Another a;
    a.ClassX::f();   

    // Why would this not work?
    // unambiguously refers to the one and only f() function 
    // inherited via  ClassA
    MyClass b;
    b.ClassA::f();   
}

由于虚拟继承,基类只有一个 vtable class Interface_Partial - 一旦你使用虚拟继承,"virtualness" 会感染所有派生的 class各级 es

继承是不明确的,因为 MyClass 有两个不同版本的 f() 可用 - 一个来自 ClassA,一个来自 ClassB。由于 Interface_Partial 的虚拟继承,您有两个派生的 - class 实现处于同一级别并试图覆盖相同的虚函数。声明一个虚拟基 class 使得所有派生的 classes 共享虚拟基 class,包括它的 vtable。共享虚表得到更新以包含应调用的虚函数的指针。但是因为有两个相同的 "good" 可供选择,所以无法选择一个而不是另一个。

在您给出的另一个示例中,Interface_PartialClassXClassY 的非虚拟基础 class,因此每个 class 都是重写的一个完全不同的虚函数。这对编译器来说是明确的,尽管当你调用它们时,你必须指定你想调用哪个特定的f()

您可以通过在 MyClass.

中提供 f() 的实现来解决此问题

要回答你的两个问题,我们需要了解虚函数的工作原理 -

如果你为每个 class 绘制 vtable,你就能理解为什么它会抛出不明确的继承错误

对于 Interface_Partial:它的 Vtable 将包含函数 f() 的地址及其自己的定义,即 Interface_Partial :: f().

接口 class/structure中:它有自己定义的函数g()以及从Interface_Partial继承的函数f(),它没有覆盖 .所以 Interface class 的 Vtable 将有两个函数的地址:

  1>    g() as  Interface :: g()

  2>    f() as  Interface_Partial :: f()

现在来到 ClassA_Partial :它覆盖了其父 class 的函数 f() 并给出了自己的定义,因此 ClassA_Partial 将函数 f() 为 :

ClassA_Partial :: f()

现在是主要部分:

如果你看到 ClassA 它继承自 InterfaceClassA_Partial 并覆盖 g() 但 不是 f()。所以当编译器看到这个时,它会感到困惑,因为现在它将有 f()

的两个定义
 1> as   Interface_Partial :: f()   
 2> as   ClassA_Partial :: f()

选择哪一个? Interface_Partial 或 ClassA_Partial !所以即使你像

那样做也会抛出错误
 b.ClassA::f();

因为两个不同版本的 f()