Z.H*_*.Hc 4 c++ virtual-functions sizeof memory-layout vptr
我认为sizeof(Base)应该是12。为什么是16?
没有虚函数,我得到4和8。
class Base{
public:
int i;
virtual void Print(){cout<<"Base Print";}
};
class Derived:public Base{
public:
int n;
virtual void Print(){cout<<"Derived Print";}
};
int main(){
Derived d;
cout<<sizeof(Base)<<","<<sizeof(d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
预期结果?12?16
实际结果?16?16
为什么sizeof(Base)与sizeof(Derived)没有不同
由于编译器引入的对齐方式。
那是依赖于体系结构的,但是为了简单起见,我假设我们引用的是64位体系结构。
类型的对齐方式Base是8字节:
alignOfBase(): # @alignOfBase()
mov eax, 8
ret
Run Code Online (Sandbox Code Playgroud)
的布局Base由变量成员(int)和虚拟表(vtptr)组成。
如果我们假设一个“通用”架构,则:
int 是4个字节的大小。vtptr是一个指针。在64位体系结构上为8字节大小。4 + 8 = 12如您所料,我们应该有的总和。
但是,我们需要记住Baseis 的对齐方式8 bytes。因此,连续Base类型应存储在8的位置倍数中。
为了保证这一点,编译器为引入了填充Base。这Base就是16字节大小的原因。
例如,如果我们考虑2个连续的Base(base0和base1),而没有填充:
0: vtptr (base 0) + 8
8: int (base 0) + 4
12: vtptr (base 1) + 8 <--- Wrong! The address 12 is not multiple of 8.
20: int (base 1) + 4
Run Code Online (Sandbox Code Playgroud)
带填充:
0: vtptr (base 0) + 8
8: int (base 0) + 4+4 (4 padding)
16: vtptr (base 1) +8 <--- Fine! The adress 16 is multiple of 8.
24: int (base 1) +4+4 (4 padding)
Run Code Online (Sandbox Code Playgroud)
同样的故事是关于Derived类型的。
的布局Derived应为:vtptr + int + int,即8 + 4 + 4 = 16。
的对齐Derived方式8也是:
alignOfDerived(): # @alignOfDerived()
mov eax, 8
ret
Run Code Online (Sandbox Code Playgroud)
实际上,在这种情况下,无需引入填充以保持Derived与内存对齐。布局尺寸将与实际尺寸相同。
0: vtptr (Derived 0)
8: int (Derived 0)
12: int (Derived 0)
16: vtptr (Derived 1) <---- Fine. 16 is multiple of 8.
24: int (Derived 1)
28: int (Derived 1)
Run Code Online (Sandbox Code Playgroud)