当在其层次结构中具有菱形继承的类的多重继承时,函数的模糊继承
Posted
技术标签:
【中文标题】当在其层次结构中具有菱形继承的类的多重继承时,函数的模糊继承【英文标题】:Ambiguous inheritance of function when multiple inheritance of classes that themselves have diamond inheritance in their hierarchy 【发布时间】:2015-02-17 07:35:53 【问题描述】:单词描述(下面的代码):我有一个提供类集合的库。对于每组类,我们有两个具体的类型,(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();
【问题讨论】:
幸运的是,上面示例中的“库”是我自己的代码——为了保持理智,我已经摆脱了钻石继承。但是 - 我对上述方法不起作用的技术原因感兴趣。 【参考方案1】:要回答你的两个问题,我们需要了解虚函数的工作原理 -
如果您为每个类绘制 vtable,那么您就可以理解为什么它会引发模棱两可的继承错误
对于Interface_Partial:它的Vtable将包含函数f()的地址和它自己的定义,即Interface_Partial :: f()。
在 Interface 类/结构中:它具有具有自己定义的函数 g() 以及从未覆盖的 Interface_Partial 继承的函数 f()。所以 Interface 类的 Vtable 将有两个函数的地址:
1> g() as Interface :: g()
2> f() as Interface_Partial :: f()
现在来到 ClassA_Partial :它从其父类中重写了函数 f() 并给出了自己的定义,因此 ClassA_Partial 的 vtable 将具有函数 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() 的两个不同版本
【讨论】:
我还是不太明白你的解释。如果我实例化ClassA
,那么ClassA::f()
由于虚拟继承是明确的,所以我仍然认为b.ClassA::f()
是明确的。
因为 ClassA 有两个函数 f() 的定义,一个来自 Interface_Partial,另一个来自 ClassA_Partial。由于您使用virutal继承Interface和ClassA_Partial,因此它们将拥有函数f()的一份副本,但是classA_Partial覆盖了f()并创建了自己的f()版本,现在当您继承这两个Interface和ClassA_Partial时,在类中A 你会得到两个不同版本的 f()。【参考方案2】:
由于虚拟继承,基类Interface_Partial只有一个vtable——一旦使用虚拟继承,“虚拟性”就会感染所有层级的所有派生类
继承是模棱两可的,因为MyClass
有两个不同版本的 f() 可用——一个来自ClassA
,一个来自ClassB
。由于Interface_Partial
的虚拟继承,您有两个处于同一级别的派生类实现并试图覆盖相同的虚拟函数。声明一个虚拟基类使所有派生类共享虚拟基类,包括它的 vtable。共享的 vtable 被更新以包含应该调用的虚函数的指针。但由于有两个同样“好”的可供选择,因此没有办法选择其中一个。
在您给出的另一个示例中,Interface_Partial
是ClassX
和ClassY
的非虚拟基类,因此每个类都覆盖了完全不同的虚拟函数。这对编译器来说是明确的,尽管当你调用它们时,你必须指定你想调用哪个特定的f()
。
您可以通过在MyClass
中提供f()
的实现来解决此问题。
【讨论】:
我不明白这与Another
类示例有何不同,尽管在同一级别有两个派生类实现,但我们毫无歧义地继承了ClassX
和ClassY
。你能澄清一下吗?
那么是不是虚拟继承会向下传递给子类呢?即使我只想知道ClassA
和ClassB
- 我仍然需要知道它们中的每一个实际上都继承了f()
,这意味着如果我非虚拟 继承ClassA
并且ClassB
编译器仍在尝试虚拟继承 f()
并解析单个函数,即使我实际上想要 ClassA::f()
和 ClassB::f()
?
@Zero,因为虚拟继承,基类Interface_Partial
只有一个vtable——一旦使用虚拟继承,“虚拟性”就会感染所有层级的所有派生类。跨度>
我在答案中添加了您之前的评论 - 因为对我来说,这是我真的不明白的一条信息。谢谢。以上是关于当在其层次结构中具有菱形继承的类的多重继承时,函数的模糊继承的主要内容,如果未能解决你的问题,请参考以下文章
C++反汇编第四讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式.