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

Hol*_*Cat 11 c++

考虑以下示例:

#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?
}
Run Code Online (Sandbox Code Playgroud)

(运行在boltbolt上)

在这里,您可以看到,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)。

Ahm*_*ter 4

因为编译器在struct A后面添加了一个字节填充

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

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

来自微软

每个数据对象都有对齐要求。对于结构,要求的是其最大的成员。每个对象都分配一个偏移量,以便 offset %alignment-requirement == 0

https://learn.microsoft.com/en-us/cpp/c-language/storage-and-alignment-of-structs?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';

}
Run Code Online (Sandbox Code Playgroud)

输出:

1 0000007A45B7FBB4
1 0000007A45B7FBB5
1 0000007A45B7FBB4
8 0000007A45B7FC18 0000007A45B7FC20
16 0000007A45B7FC38 0000007A45B7FC40 0000007A45B7FC41
Run Code Online (Sandbox Code Playgroud)

正如你所看到的, a 和 b 永远不会相互重叠,并且在多重继承上 vptr 每个都有自己的指针值

VC2019 x64 build 编译的注释