Pas*_*mer 6 c++ multiple-inheritance vtable memory-layout vptr
对于其clas(子)具有单继承的对象,通常需要多少个vptrs,其基类为多个继承base1和base2.确定对象提供了多少个vpt的策略是什么,它提供了几个单继承和多继承.虽然标准没有指定vptrs,但我只是想知道一个实现如何实现虚函数.
你为什么在乎?简单的答案就足够了,但我想你想要更完整的东西.
这不是标准的一部分,因此任何实现都可以按照自己的意愿自由进行,但一般的经验法则是在使用虚拟表指针的实现中,作为第0个近似值,用于动态调度,最多需要许多指向虚拟表的指针,因为有些类将新的虚方法添加到层次结构中.(在某些情况下,可以扩展虚拟表,并且基本和派生类型共享一个vptr)
// some examples:
struct a { void foo(); }; // no need for virtual table
struct b : a { virtual foo1(); }; // need vtable, and vptr
struct c : b { void bar(); }; // no extra virtual table, 1 vptr (b) suffices
struct d : b { virtual bar(); }; // extra vtable, need b.vptr and d.vptr
struct e : d, b {}; // 3 vptr, 2 for the d subobject and one for
// the additional b
struct f : virtual b {};
struct g : virtual b {};
struct h : f, g {}; // single vptr, only b needs vtable and
// there is a single b
Run Code Online (Sandbox Code Playgroud)
基本上每个需要自己动态调度的类型的子对象(不能直接重用父对象)都需要自己的虚拟表和vptr.
实际上编译器将不同的vtable合并到一个vtable中.当在d函数集中添加新的虚函数时b,编译器会通过将新的插槽附加到vtable的末尾将可能的两个表合并为一个表,因此vtable d将是vtable 的扩展版本.b最后保留二进制兼容性的额外元素(即dvtable可以解释为b访问可用方法的vtable b),并且d对象将具有单个vptr.
在多重继承的情况下,事情变得有点复杂,因为每个基础需要与完整对象的子对象具有相同的布局,而不是它是单独的对象,因此将有额外的vptrs指向完整对象中的不同区域虚函数表.
最后,在虚拟继承的情况下,事情变得更加复杂,并且可能有多个vtable用于同一个完整对象,随着构造/破坏的发展,vptr会被更新(vptr总是在构造/破坏演变时更新,但没有虚拟继承vptr将指向base的vtable,而在虚拟继承的情况下,将有多个相同类型的vtable)
没有指定任何关于 vptr/vtable 的东西,所以这将取决于编译器的细节,但几乎每个现代编译器都处理简单的情况(我写“几乎”以防万一)。
你被警告了。
如果您从基类继承,并且它们有一个 vptr,那么您的类中自然会有许多继承的 vptr。
问题是:编译器什么时候会向已经继承了 vptr 的类添加 vptr?
编译器会尽量避免添加多余的 vptr:
struct B {
virtual ~B();
};
struct D : B {
virtual void foo();
};
Run Code Online (Sandbox Code Playgroud)
这里B有一个vptr,所以D没有得到自己的vptr,它重用了现有的vptr;的 vtableB扩展为条目foo()。vtable forD是从vtable for中“派生”出来的B,伪代码:
struct B_vtable {
typeinfo *info; // for typeid, dynamic_cast
void (*destructor)(B*);
};
struct D_vtable : B_vtable {
void (*foo)(D*);
};
Run Code Online (Sandbox Code Playgroud)
再次强调:这是对真正的 vtable 的简化,以获得想法。
对于非虚拟单继承,实现之间几乎没有变化的余地。对于虚拟继承,编译器之间有更多的变化。
struct B2 : virtual A {
};
Run Code Online (Sandbox Code Playgroud)
有一个从B2*to的转换A*,所以一个B2对象必须提供这个功能:
A*会员offset_of_A_from_B2offset_of_A_from_B2在 vtable 中通常,类不会重用其虚拟基类的 vptr(但在非常特殊的情况下可以)。
| 归档时间: |
|
| 查看次数: |
4332 次 |
| 最近记录: |