想象一下标准的钻石继承。A 类定义了纯虚函数 fx,B 类定义了 fx 的实现,C 类和 D 类对 fx 没有任何作用。当尝试在 D 类的实例上调用 fx 时,您将收到“模糊函数调用”错误,尽管 fx 只有一种实现。这可以通过 B 和 C 以虚拟方式从 A 继承来解决。这是解决问题的正确方法吗?虚拟继承究竟如何处理虚函数表的合并?
A--->B--->D
\--->C--------^
想象一下标准的钻石继承。A 类定义了纯虚函数 fx,B 类定义了 fx 的实现,C 类和 D 类对 fx 没有任何作用。当尝试在 D 类的实例上调用 fx 时,您将收到“模糊函数调用”错误,尽管 fx 只有一种实现。这可以通过 B 和 C 以虚拟方式从 A 继承来解决。这是解决问题的正确方法吗?虚拟继承究竟如何处理虚函数表的合并?
A--->B--->D
\--->C--------^
... 注意,Herb Sutter 写了 3 篇关于多重继承的优秀文章(1) here,(2) here和(3) here。他在这里的本周大师中写了一大堆有用的文章。强烈推荐 ...
首先,我不确定我的层次结构是否正确。我认为它是这样的:
struct A {
virtual void F() = 0;
};
struct B : A { void F() { } };
struct C : A { };
struct D : B, C { };
A
嗯,D 是抽象的,因为在 D 类型的对象中有两个子对象:一个B
通过 B 的格子变得具体,另一个在通过的格子中仍然是抽象的C
。我认为你有一个指针D
并尝试调用F
. 是的,出现了歧义,因为编译器F
在两个单独的格中找到了两个函数:
D -> B::F
D -> C -> A::F
看起来像这样:
F() F()
A A
| |
F() B C
\ /
D
您可以通过虚拟地从 A 派生来正式解决这种情况:
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
是继承的 virtual。
这是否是您特定问题的正确解决方案 - 当然不确定。通常有比从类派生虚拟更好的方法。关于合并虚函数表的问题 - 这完全取决于实现。,据我所知,如果我们派生虚拟GCC
,它将在 的虚拟表中保留一个指向 A 实例的指针。D
这是解决问题的正确方法吗?
“钻石”继承是有问题的,解决方案的正确解释需要一点解释。我建议您阅读 Meyers 的Effective C++的以下章节: