为什么重复的空基存储不与 vtable 指针重叠?

Why doesn't storage for a duplicate empty base overlap with a vtable pointer?

本文关键字:vtable 指针 重叠 存储 为什么      更新时间:2023-10-16

考虑这个例子:

#include <iostream>
int main()
{
struct A {};
struct B : A {};
struct C : A, B {};
std::cout << sizeof(A) << 'n'; // 1
std::cout << sizeof(B) << 'n'; // 1
std::cout << sizeof(C) << 'n'; // 2, because of a duplicate base
struct E : A {virtual ~E() {}};
struct F : A, B {virtual ~F() {}};
std::cout << sizeof(E) << 'n'; // 8, the base overlaps the vtable pointer
std::cout << sizeof(F) << 'n'; // 16, but why?
}

(在导螺杆上运行(

在这里,您可以看到,对于struct E,空基类(1字节大(使用与vtable指针相同的存储,正如预期的那样。

但对于具有重复空基的struct F,这种情况不会发生。是什么原因造成的?

我在GCC、Clang和MSVC上得到了同样的结果。以上结果适用于x64,因此sizeof(void *) == 8


有趣的是,对于struct G : A, B {void *ptr;};,GCC和Clang确实执行EBO(大小为8(,但MSVC不执行(大小为16(。

因为编译器在结构A 后添加了一个字节的填充

F{vptr(8(+来自A的0个成员+1个填充(因为A为空(+来自b的0个}=9则编译器添加7个字节的填充以对齐结构体的存储;

E{vptr(8(+A的0个成员}=8无需填充

来自Microsoft

每个数据对象都有一个对齐要求。对于结构要求是其成员中最大的。每个对象都已分配偏移,使得偏移%对准要求==0

https://learn.microsoft.com/en-us/cpp/c-language/storage-and-alignment-of-structures?view=vs-2019年

编辑:

这是我的演示:

int main()
{
C c;
A* a = &c;
B* b = &c;
std::cout << sizeof(A) << " " << a << 'n'; 
std::cout << sizeof(B) << " " << b << 'n'; 
std::cout << sizeof(C) << " " << &c << 'n'; 
E e;
a = &e;
std::cout << sizeof(E) <<" " << &e << " " << a << 'n'; 
F f;
a = &f;
b = &f;
std::cout << sizeof(F) << " " << &f << " " << a << " " << b << 'n';
}

输出:

1 0000007A45B7FBB4
1 0000007A45B7FBB5
1 0000007A45B7FBB4
8 0000007A45B7FC18 0000007A45B7FC20
16 0000007A45B7FC38 0000007A45B7FC40 0000007A45B7FC41

正如你所看到的&b从不相互重叠,并且在多重继承上具有vptr,每个vptr都有自己的指针值

由VC2019 x64版本编译的说明