当 类 的多重继承本身在其层次结构中具有菱形继承时,功能继承不明确
Ambiguous inheritance of function when multiple inheritance of classes that themselves have diamond inheritance in their hierarchy
文字描述(下面的代码):我有一个库,提供了classes的集合。对于每组 class,我们有两个具体类型,(ClassA_Partial
、ClassA
)、(ClassB_Partial
、ClassB
) 等。这些实现中的每一个 (Interface_Partial
, Interface
) 分别。此外,Interface
是一个 Interface_Partial
,每个Class?
是一个 Class?_Partial
- 创建钻石继承模式,顶部虚拟继承。
为什么在继承 ClassA
和 ClassB
时,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_Partial
是 ClassX
和 ClassY
的非虚拟基础 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 它继承自 Interface 和 ClassA_Partial 并覆盖 g() 但 不是 f()。所以当编译器看到这个时,它会感到困惑,因为现在它将有 f()
的两个定义
1> as Interface_Partial :: f()
2> as ClassA_Partial :: f()
选择哪一个? Interface_Partial 或 ClassA_Partial !所以即使你像
那样做也会抛出错误
b.ClassA::f();
因为两个不同版本的 f()
文字描述(下面的代码):我有一个库,提供了classes的集合。对于每组 class,我们有两个具体类型,(ClassA_Partial
、ClassA
)、(ClassB_Partial
、ClassB
) 等。这些实现中的每一个 (Interface_Partial
, Interface
) 分别。此外,Interface
是一个 Interface_Partial
,每个Class?
是一个 Class?_Partial
- 创建钻石继承模式,顶部虚拟继承。
为什么在继承 ClassA
和 ClassB
时,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_Partial
是 ClassX
和 ClassY
的非虚拟基础 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 它继承自 Interface 和 ClassA_Partial 并覆盖 g() 但 不是 f()。所以当编译器看到这个时,它会感到困惑,因为现在它将有 f()
的两个定义 1> as Interface_Partial :: f()
2> as ClassA_Partial :: f()
选择哪一个? Interface_Partial 或 ClassA_Partial !所以即使你像
那样做也会抛出错误 b.ClassA::f();
因为两个不同版本的 f()