B
and C
inherit from a class A
, and a class D
inherits from both B
and C
, then D
will contain two copies of A
s member variables: one via B
, and one via C
. These will be accessible independently, using scope resolution.
Instead, if classes B
and C
inherit virtually from class A
, then objects of class D
will contain only one set of the member variables from class A
.
This feature is most useful for D
in the example above) the virtual base (A
) acts as though it were the direct base class of D
, not a class derived indirectly through a base (B
or C
).
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
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:
bat
to either base class subobject:
Eat
, the same disambiguation, or explicit qualification is needed: static_cast(bat).Eat()
or static_cast(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.
In this case, the double inheritance of Animal
is probably unwanted, as we want to model that the relation (Bat
is an Animal
) exists only once; that a Bat
is a Mammal
and is a WingedAnimal
does not imply that it is an Animal
twice: an Animal
base class corresponds to a contract that Bat
implements (the "is a" relationship above really means "''implements the requirements of''"), and a Bat
only implements the Animal
contract once. The real world meaning of "''is a'' only once" is that Bat
should have only one way of implementing Eat
, not two different ways, depending on whether the Mammal
view of the Bat
is eating, or the WingedAnimal
view of the Bat
. (In the first code example we see that Eat
is not overridden in either Mammal
or WingedAnimal
, so the two Animal
subobjects will actually behave the same, but this is just a degenerate case, and that does not make a difference from the C++ point of view.)
This situation is sometimes referred to as diamond inheritance (see The solution
We can re-declare our classes as follows:Animal
portion of Bat::WingedAnimal
is now the ''same'' Animal
instance as the one used by Bat::Mammal
, which is to say that a Bat
has only one, shared, Animal
instance in its representation and so a call to Bat::Eat
is unambiguous. Additionally, a direct cast from Bat
to Animal
is also unambiguous, now that there exists only one Animal
instance which Bat
could be converted to.
The ability to share a single instance of the Animal
parent between Mammal
and WingedAnimal
is enabled by recording the memory offset between the Mammal
or WingedAnimal
members and those of the base Animal
within the derived class. However this offset can in the general case only be known at runtime, thus Bat
must become (vpointer
, Mammal
, vpointer
, WingedAnimal
, Bat
, Animal
). There are two Animal
. In this example, one for Mammal
and one for WingedAnimal
. The object size has therefore increased by two pointers, but now there is only one Animal
and no ambiguity. All objects of type Bat
will use the same vpointers, but each Bat
object will contain its own unique Animal
object. If another class inherits from Mammal
, such as Squirrel
, then the vpointer in the Mammal
part of Squirrel
will generally be different to the vpointer in the Mammal
part of Bat
though they may happen to be the same if the Squirrel
class be the same size as Bat
.
Additional Example of Several Ancestors
This example to illustrates a case where base classA
has a constructor variable msg
and an additional ancestor E
is derived from grandchild class D
.
A / \ B C \ / D , EHere,
A
must be constructed in both D
and E
. Further, inspection of the variable msg
illustrates how class A
becomes a direct base class of its deriving class, as opposed to a base class of any intermediate deriving classed between A
and the final deriving class. The code below may be explored interactivelPure Virtual Methods
Suppose a pure virtual method is defined in the base class. If a deriving class inherits the base class virtually, then the pure virtual method does not need to be defined in that deriving class. However, if the deriving class does not inherit the base class virtually, then all virtual methods must be defined. The code below may be explored interactivelReferences
{{C++ programming language Class (computer programming) C++ sv:Multipelt arv tr:Çoklu kalıtım