class RootBase{
public:
RootBase():ai(12){}
virtual void fas(){
printf("%p \n", this);
}
private:
int ai;
};
class Base : virtual public RootBase{
public:
Base():bai(1){}
virtual void fas(){
}
virtual void fa(){
}
private:
int bai;
};
Base *pBase = new Base;
我测试了关于类的内存位置的虚拟继承关系情况。结果让我感到惊讶,因为Base的大小是24字节。我可以理解包含虚函数表指针,虚基表指针和成员变量的20字节。
pBase指向的Base对象的内存分布是:
60 77 41 00 68 77 41 00 01 00 00 00 00 00 00 00 54 77 41 00 0c 00 00 00
但是我无法理解第13-16字节的含义,0x00000000,一个NULL(x86 32位中的整数0)。四字节0有什么作用? (OS:win xp,IDE:visual studio 8.0)
我也认为整数0表示对齐填充,但没有理由填充到8个字节。
答案 0 :(得分:3)
这直接取自您所描述的类的对象布局的转储。我希望它能回答你的问题。通过更多的研究,我发现了vtordisp
类Base
。是从使用虚拟基础声明的类的构造函数或析构函数调用虚函数时使用的偏移量。显然它是告诉他们你的虚拟功能表在哪里。
来自Jonathan Caves, MSFT,超过5年前:
很少使用它 - 但我们必须将它添加到从虚拟基类继承的类中,并覆盖虚函数,以防用户在构造函数或析构函数中调用虚函数。
注意:对于所有行中的1>
前言感到抱歉。责怪微软,它们的工具。
1> class RootBase size(8):
1> +---
1> 0 | {vfptr}
1> 4 | ai
1> +---
1>
1> RootBase::$vftable@:
1> | &RootBase_meta
1> | 0
1> 0 | &RootBase::fas
1>
1> RootBase::fas this adjustor: 0
1>
1>
1> class Base size(24):
1> +---
1> 0 | {vfptr}
1> 4 | {vbptr}
1> 8 | bai
1> +---
1> 12 | (vtordisp for vbase RootBase)
1> +--- (virtual base RootBase)
1> 16 | {vfptr}
1> 20 | ai
1> +---
1>
1> Base::$vftable@Base@:
1> | &Base_meta
1> | 0
1> 0 | &Base::fa
1>
1> Base::$vbtable@:
1> 0 | -4
1> 1 | 12 (Based(Base+4)RootBase)
1>
1> Base::$vftable@RootBase@:
1> | -16
1> 0 | &(vtordisp) Base::fas
1>
1> Base::fas this adjustor: 16
1> Base::fa this adjustor: 0
1>
1> vbi class offset o.vbptr o.vbte fVtorDisp
1> RootBase 16 4 4 1
使用完全相同的代码,但使RootBase
成为常规基类(即,不是virtual public RootBase
,只需public RootBase
)对对象布局有显着影响:
1> class RootBase size(8):
1> +---
1> 0 | {vfptr}
1> 4 | ai
1> +---
1>
1> RootBase::$vftable@:
1> | &RootBase_meta
1> | 0
1> 0 | &RootBase::fas
1>
1> RootBase::fas this adjustor: 0
1>
1>
1> class Base size(12):
1> +---
1> | +--- (base class RootBase)
1> 0 | | {vfptr}
1> 4 | | ai
1> | +---
1> 8 | bai
1> +---
1>
1> Base::$vftable@:
1> | &Base_meta
1> | 0
1> 0 | &Base::fas
1> 1 | &Base::fa
1>
1> Base::fas this adjustor: 0
1> Base::fa this adjustor: 0
请注意,随着虚拟基数消失,不再存储“who-am-i”偏移量,这似乎可以很好地清理对象格式。