Considere este ejemplo:
#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?
}
Aquí puede ver que para struct Ela clase base vacía (que es 1 byte grande) usa el mismo almacenamiento que el puntero vtable, como se esperaba.
Pero para struct F, que tiene una base vacía duplicada, esto no sucede. ¿Qué causa esto?
Obtengo el mismo resultado en GCC, Clang y MSVC. Los resultados anteriores son para x64, entonces sizeof(void *) == 8.
Curiosamente, para struct G : A, B {void *ptr;};GCC y Clang realizan EBO (el tamaño es 8), pero MSVC no (el tamaño es 16).
Cy F? Después de todo, 2 * sizeof(void*) == 16en x86_64 como has dicho. El compilador no puede optimizar completamente (como dijo Story Teller) y tampoco lo hace.
A, heredado vía B. Eso está bien. Solo si realmente intentas acceder a él, como en tu ejemplo, obtienes un error.
C(que heredan deA,B) se obtiene resultado diferente que heredar formaAyBdirectamente