为什么虚拟继承即使不涉及虚函数也需要一个vtable?

2023-12-21

我读过这个问题:C++ 虚拟类继承对象大小问题 https://stackoverflow.com/questions/57481249/c-virtual-class-inheritance-object-size-issue,并且想知道为什么虚拟继承会在类中产生一个额外的 vtable 指针。

我在这里找到一篇文章:https://en.wikipedia.org/wiki/Virtual_inheritance https://en.wikipedia.org/wiki/Virtual_inheritance

这告诉我们:

然而,在一般情况下,这个偏移量只能在运行时知道,...

我不明白这里与运行时相关的是什么。完整的类继承层次结构在编译时就已知。我了解虚拟函数和基指针的使用,但虚拟继承没有这样的东西。

有人可以解释为什么某些编译器(Clang/GCC)使用 vtable 实现虚拟继承,以及如何使用它runtime?

BTW,我也看到了这个问题:虚拟继承情况下的 vtable https://stackoverflow.com/questions/44989780/vtable-in-case-of-virtual-inheritance,但它只指向与虚函数相关的答案,这不是我的问题。


完整的类继承层次结构在编译时就已知。

确实如此;因此,如果编译器知道最派生对象的类型,那么它就知道该对象内每个子对象的偏移量。为此,不需要 vtable。

例如,如果B and C两者实际上都源自A, and D源自两者B and C,然后在以下代码中:

D d;
A* a = &d;

的转换来自D* to A*最多就是给地址添加一个静态偏移量。

然而,现在考虑一下这种情况:

A* f(B* b) { return b; }
A* g(C* c) { return c; }

Here, f必须能够接受指向任何B对象,包括一个B可能是某个对象的子对象的对象D对象或其他一些最派生类对象的对象。编译时f,编译器不知道完整的派生类集B.

If the B对象是最派生的对象,那么A子对象将位于一定的偏移量处。但如果B对象是a的一部分D目的?这D对象只包含一个A对象,并且它不能位于其通常的偏移处both the B and C子对象。所以编译器必须选择一个位置A的子对象D,然后它必须提供一种机制,以便某些带有B* or C*可以找出在哪里A子对象是。这仅取决于最派生类型的继承层次结构——因此 vptr/vtable 是一种合适的机制。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么虚拟继承即使不涉及虚函数也需要一个vtable? 的相关文章

随机推荐