Virtual inheritance
From Wikipedia, the free encyclopedia
- For inheritance of virtual functions, see virtual function.
In C++, virtual inheritance is a kind of inheritance that solves some of the problems caused by multiple inheritance (particularly the "diamond problem") by clarifying ambiguity over which ancestor class members to use. It is used when inheritance is representing restrictions of a set rather than composition of parts. A multiply-inherited base class is denoted as virtual with the virtual
keyword.
[edit] The problem
Consider the following class hierarchy.
class Animal { virtual void Eat(); }; class Mammal : public Animal { public: virtual Color GetHairColor(); }; class WingedAnimal : public Animal { public: virtual void Flap(); }; // A bat is a winged mammal class Bat : public Mammal, public WingedAnimal {};
But how does a Bat
Eat()
? As declared above, a call to Bat.Eat()
is ambiguous. One would have to call either Bat.WingedAnimal::Eat()
or Bat.Mammal::Eat()
. The problem is that semantics of conventional multiple inheritance do not model reality. In a sense, an Animal
is only an Animal
once; a Bat
is a Mammal
and a WingedAnimal
, but the Animal
ness of a Bat
's Mammal
ness is the same Animal
ness as that of its WingedAnimal
ness.
This is the problem that virtual inheritance works to solve.
[edit] Class representation
Before going further it is helpful to consider how classes are represented in C++. In particular, inheritance is simply a matter of putting parent and child class one after the other in memory.
[edit] Solution
We can redeclare our classes as follows:
// Two classes virtually inheriting Animal: class Mammal : public virtual Animal { public: virtual Color GetHairColor(); }; class WingedAnimal : public virtual Animal { public: virtual void Flap(); };
// A bat is still a winged mammal class Bat : public Mammal, public WingedAnimal {};
Now the Animal
portion of Bat::WingedAnimal
is the same Animal
as the one used by Bat::Mammal
, which is to say that a Bat
has only one Animal
in its representation and so a call to Bat::Eat()
is unambiguous.
This is implemented by providing Mammal
and WingedAnimal
with a vtable since, e.g., the memory offset between the beginning of a Mammal
and of its Animal
part is unknown until runtime.