Virtual base classes, used in virtual inheritance, is a way of preventing multiple "instances" of a given class appearing in an inheritance hierarchy when using multiple inheritance.
Consider the following scenario:
class A { public: void Foo() {} };
class B : public A {};
class C : public A {};
class D : public B, public C {};
The above class hierarchy results in the "dreaded diamond" which looks like this:
A
/ \
B C
\ /
D
An instance of D will be made up of B, which includes A, and C which also includes A. So you have two "instances" (for want of a better expression) of A.
When you have this scenario, you have the possibility of ambiguity. What happens when you do this:
D d;
d.Foo(); // is this B's Foo() or C's Foo() ??
Virtual inheritance is there to solve this problem. When you specify virtual when inheriting your classes, you're telling the compiler that you only want a single instance.
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
This means that there is only one "instance" of A included in the hierarchy. Hence
D d;
d.Foo(); // no longer ambiguous
This is a mini summary. For more information, have a read of this and this. A good example is also available here.
What's happening here is called aggregate initialization. Here is the (abbreviated) definition of an aggregate from section 8.5.1 of the ISO spec:
An aggregate is an array or a class with no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions.
Now, using {0}
to initialize an aggregate like this is basically a trick to 0
the entire thing. This is because when using aggregate initialization you don't have to specify all the members and the spec requires that all unspecified members be default initialized, which means set to 0
for simple types.
Here is the relevant quote from the spec:
If there are fewer initializers in the list than there are members in the
aggregate, then each member not
explicitly initialized shall be
default-initialized.
Example:
struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };
initializes ss.a
with 1
, ss.b
with
"asdf"
, and ss.c
with the value of an
expression of the form int()
, that is,
0
.
You can find the complete spec on this topic here
Best Answer
That's virtual inheritance, you do it when you know you'll be doing multiple inheritance. That page goes into way more detail.