The memory layout and the vtable layout depend on your compiler. Using my gcc for instance, they look like this:
sizeof(int) == 4
sizeof(A) == 8
sizeof(B) == 8
sizeof(C) == 20
Note that sizeof(int) and the space needed for the vtable pointer can also vary from compiler to compiler and platform to platform. The reason why sizeof(C) == 20 and not 16 is that gcc gives it 8 bytes for the A subobject, 8 bytes for the B subobject and 4 bytes for its member int c
.
Vtable for C C::_ZTV1C: 6u entries 0 (int (*)(...))0 4 (int (*)(...))(& _ZTI1C) 8 A::funA 12 (int (*)(...))-0x00000000000000008 16 (int (*)(...))(& _ZTI1C) 20 B::funB Class C size=20 align=4 base size=20 base align=4 C (0x40bd5e00) 0 vptr=((& C::_ZTV1C) + 8u) A (0x40bd6080) 0 primary-for C (0x40bd5e00) B (0x40bd60c0) 8 vptr=((& C::_ZTV1C) + 20u)
Using virtual inheritance
class C : public virtual A, public virtual B
the layout changes to
Vtable for C C::_ZTV1C: 12u entries 0 16u 4 8u 8 (int (*)(...))0 12 (int (*)(...))(& _ZTI1C) 16 0u 20 (int (*)(...))-0x00000000000000008 24 (int (*)(...))(& _ZTI1C) 28 A::funA 32 0u 36 (int (*)(...))-0x00000000000000010 40 (int (*)(...))(& _ZTI1C) 44 B::funB VTT for C C::_ZTT1C: 3u entries 0 ((& C::_ZTV1C) + 16u) 4 ((& C::_ZTV1C) + 28u) 8 ((& C::_ZTV1C) + 44u) Class C size=24 align=4 base size=8 base align=4 C (0x40bd5e00) 0 vptridx=0u vptr=((& C::_ZTV1C) + 16u) A (0x40bd6080) 8 virtual vptridx=4u vbaseoffset=-0x0000000000000000c vptr=((& C::_ZTV1C) + 28u) B (0x40bd60c0) 16 virtual vptridx=8u vbaseoffset=-0x00000000000000010 vptr=((& C::_ZTV1C) + 44u)
Using gcc, you can add -fdump-class-hierarchy
to obtain this information.