class A {
int i;
};
class B : public A {
int j;
};
In this example, which does not use virtual inheritance, an object of type B
can be laid out as if B
had been defined like this:
class B0 {
int i;
int j;
};
Once you introduce virtual inheritance, this doesn't work:
class C : public virtual A {
int k;
};
class D : public virtual A {
int l;
};
class E : public C, public D {
int m;
};
An object of type C
has two int
members: k
from the definition of C
and i
from the definition of A
. Similarly, an object of type D
has two int
members, l
and i
. So far, so good. The tricky part comes with class E
: it, too, has one int
member i
, because both instances of A
are virtual bases. So neither C
nor D
can't be written like B0
above, because then E
would end up with two copies of i
.
The solution is to add a layer of indirection. Objects of type C
, D
, and E
look something like this (pseudo-code, don't try to compile it):
class C0 {
int *cip = &i;
int k;
int i;
};
class D0 {
int *dip = &i;
int l;
int i;
};
class E0 {
// C0 subobect:
int *cip = &i;
int k;
// D0 subobject:
int *dip = &i;
int l;
// E data:
int *eip = &i;
int m;
int i;
};
What you're seeing in the size of E
is those extra pointers, which make it possible to have a single copy of i
regardless of how C
and D
are combined in a derived class. (In reality, each of those pointers would be a pointer to A
, since A
can certainly have more than one data member, but that's too hard to represent in this simple pseudo-code).