这是Scott Meyers 出版的德语笔记的翻译示例。考虑
class B1 {
public:
virtual void mf(); // may be overridden in derived classes
};
class B2 {
public:
virtual void mf(); // may be overridden in derived classes
};
class D: public B1, public B2 {};
void g(B2 *pb2)
{
pb2->mf(); // requires offset adjustment before calling mf?
}
仅当覆盖并真正指向 a时,才需要传递给的指针参数g()
需要偏移调整。编译器应该做什么?为调用生成代码时,D
mf
pb2
D
- 它可能不知道
D
存在。(这就是动态多态性的重点:能够在不重新编译的情况下调用未来的代码)
- 它不知道是否
pb2
指向 a D
(它只知道仅在运行时)。
因为多态类需要对未来可能的进一步派生的无限集保持灵活,所以该问题通常通过以下方式解决
- 创建处理偏移调整的特殊 vtbl。
- 对于派生类对象,将新的 vptr 添加到这些 vtbl,在第一个基类之后为每个基类添加一个额外的 vptr。
将所有虚函数合并到一个表中会破坏这种灵活性。请注意,多重“并行”继承D: B1, B2 {};
与“堆叠”继承不同D: M: B {};
。后者需要一个替换链,前者有两个这样的链并且不B1
兼容B2
。