4

文字描述下面的代码):我有一个提供类集合的库。对于每组类,我们有两个具体类型,( ClassA_Partial, ClassA), ( ClassB_Partial, ClassB) 等。每个都分别实现 ( Interface_Partial, Interface)。此外,Interface is a Interface_Partial和 each Class? is a Class?_Partial - 创建一个菱形继承模式,其中顶部是虚拟继承的。

为什么同时继承和Interface_Partial时函数不明确?ClassAClassB

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();   
}
4

2 回答 2

4

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

如果您为每个类绘制 vtable,您就可以理解为什么它会引发模棱两可的继承错误

在此处输入图像描述

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

接口类/结构中:它具有具有自己定义的函数 g() 以及从未覆盖的 Interface_Partial 继承的函数 f()。所以接口类的 Vtable 将有两个函数的地址:

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

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

现在来到ClassA_Partial:它已经从其父类覆盖了函数 f() 并给出了自己的定义,因此ClassA_Partial的 vtable将具有函数 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() 的两个不同版本

于 2015-02-18T11:54:35.243 回答
2

由于虚拟继承,基类Interface_Partial只有一个vtable——一旦使用虚拟继承,“虚拟性”会感染所有级别的所有派生类

继承是模棱两可的,因为MyClass有两个不同版本的 f() 可用 - 一个 fromClassA和一个 from ClassB。由于 的虚拟继承Interface_Partial,您有两个处于同一级别的派生类实现并试图覆盖相同的虚拟函数。声明一个虚拟基类使所有派生类共享虚拟基类,包括它的 vtable。共享的 vtable 被更新以包含应该调用的虚函数的指针。但是由于有两个同样“好”的可供选择,所以没有办法选择一个。

在您给出的另一个示例中, andInterface_Partial是一个非虚拟基类,因此每个类都覆盖了一个完全不同的虚拟函数。这对编译器来说是明确的,尽管当您调用它们时,您必须指定要调用的具体内容。 ClassXClassYf()

您可以通过提供f()in的实现来解决此问题MyClass

于 2015-02-17T08:12:43.910 回答