想象一下标准的钻石继承。 A类定义纯虚函数fx,B类定义fx的实现,C和D类对fx不执行任何操作。当试图在类D的实例上调用fx时,你会得到'模糊函数调用'错误,尽管只有一个fx实现。这可以通过以虚拟方式从A继承的B和C来解决。这是问题的正确的解决方案吗?虚拟继承如何处理虚函数表的合并?
A --->乙---> d
\ ---&以及c ------ ^
答案 0 :(得分:19)
...注意,Herb Sutter撰写了3篇关于多重继承的优秀文章(1) here,(2) here和(3) here。他在本周的大师here中写了另外一堆有用的文章。强烈推荐......
首先,我不确定我的层次结构是否正确。我认为是这样的:
struct A {
virtual void F() = 0;
};
struct B : A { void F() { } };
struct C : A { };
struct D : B, C { };
嗯,D是抽象的,因为在D类型的对象中有两个A
子对象:一个由B
通过B的格子具体化,一个仍然是抽象的格子经过C
。我认为你有一个指向D
的指针,并尝试拨打F
。是的,出现了歧义,因为编译器在两个不同的格子中找到两个函数F
:
D -> B::F
D -> C -> A::F
看起来像这样:
F() F()
A A
| |
F() B C
\ /
D
您可以通过虚拟衍生来正式解决这种情况:
struct B : virtual A { void F() { } };
struct C : virtual A { };
struct D : B, C { };
然后你有这种情况,称为钻石继承:
F()
A
/ \
F() B C
\ /
D
在进行查找时,它发现B::F
覆盖A::F
。虽然仍然可以通过A::F
来达到D::C::A
,但这不再是歧义,因为A
是虚拟继承的。
这是否是您特定问题的正确解决方案 - 当然不确定。除了从类中派生虚拟之外,通常有更好的方法。关于合并虚函数表的问题 - 这完全取决于实现。据我所知,GCC
将保留指向D
虚拟表中的一个实例的指针,如果我们派生虚拟的话。
答案 1 :(得分:3)
这是问题的正确的解决方案吗?
“Diamond”继承存在问题,解决方案的正确解释需要一些解释。我建议您阅读Meyers的 Effective C ++ 的以下章节: