Virtual inheritance is a technique used in C++, where a particular base class in an inheritance hierarchy is declared to share its member data instances with any other inclusions of that same base in further derived classes. For example, if class A is normally (non-virtually) derived from class X (assumed to contain data members), and if class B is also derived from class X, and class C inherits from both classes A and B, it will contain two sets of the data members associated with class X (accessible independently, often with suitable disambiguating qualifiers). But if class A is virtually derived from class X instead, then objects of class C will contain only one set of the data members from class X.
This feature is most useful for multiple inheritance, as it makes the virtual base a common subobject for the deriving class and all classes that are derived from it. This can be used to avoid the diamond problem by clarifying ambiguity over which ancestor class to use, as from the perspective of the deriving class (C in the example above) the virtual base (X) acts as though it were the direct base class of C, not a class derived indirectly through its base (A).
It is used when inheritance represents restriction of a set rather than composition of parts. In C++, a base class intended to be common throughout the hierarchy is denoted as virtual with the virtual
keyword.
Consider the following class hierarchy.
As declared above, a call to bat.eat()
is ambiguous because there are two Animal
(indirect) base classes in Bat
, so any Bat
object has two different Animal
base class subobjects. So an attempt to directly bind a reference to the Animal
subobject of a Bat
object would fail, since the binding is inherently ambiguous:
To disambiguate, one would have to explicitly convert bat
to either base class subobject:
In order to call eat()
, the same disambiguation, or explicit qualification is needed: static_cast<Mammal&>(bat).eat()
or static_cast<WingedAnimal&>(bat).eat()
or alternatively bat.Mammal::eat()
and bat.WingedAnimal::eat()
. Explicit qualification not only uses an easier, uniform syntax for both pointers and objects but also allows for static dispatch, so it would arguably be the preferable method.