为什么 sizeof(Base) 与 sizeof(Derived) 没有区别
因为编译器引入了对齐。
那是依赖于架构的,但为了简单起见,我假设我们指的是 64 位架构。
场景 64 位/Clang 8.0。
类型的对齐方式Base
是8
字节:
alignOfBase(): # @alignOfBase()
mov eax, 8
ret
的布局Base
由变量成员(int
)和虚拟表(vtptr
)组成。
如果我们假设一个“通用”架构,其中:
int
是 4 字节大小。
vtptr
是一个指针。在 64 位架构上是 8 字节大小。
4 + 8 = 12
如您所料,我们应该有 的总和。
但是,我们需要记住 is 的对齐Base
方式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
带填充:
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)
同样的故事也适用于Derived
类型。
的布局Derived
应该是:vtptr + int + int
,即8 + 4 + 4 = 16
。
的对齐方式Derived
也是8
:
alignOfDerived(): # @alignOfDerived()
mov eax, 8
ret
实际上,在这种情况下,不需要引入填充来保持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)