Considere este exemplo:
#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?
}
Aqui você pode ver que, para struct Ea classe base vazia (que tem 1 byte de largura), usa o mesmo armazenamento que o ponteiro vtable, conforme o esperado.
Mas para struct F, que tem uma base vazia duplicada, isso não acontece. O que causa isso?
Eu obtenho o mesmo resultado no GCC, Clang e MSVC. Os resultados acima são para x64, então sizeof(void *) == 8.
Curiosamente, o struct G : A, B {void *ptr;};GCC e o Clang realizam EBO (o tamanho é 8), mas o MSVC não (o tamanho é 16).
Ce F? Afinal, 2 * sizeof(void*) == 16no x86_64, como você disse. O compilador não pode otimizar completamente (como o Story Teller disse) e não.
A, herdado por B, não pode ser acessado. Está bem. Somente se você realmente tentar acessá-lo, como no exemplo, você receberá um erro.
C(que herdamA,B), obtém resultado diferente do que herdar formaAeBdiretamente