HOME

TheInfoList



OR:

Virtual inheritance is a
C++ C, or c, is the third letter in the Latin alphabet, used in the modern English alphabet, the alphabets of other western European languages and others worldwide. Its name in English is ''cee'' (pronounced ), plural ''cees''. History "C" ...
technique that ensures only one copy of a
base class In object-oriented programming, inheritance is the mechanism of basing an object or class upon another object ( prototype-based inheritance) or class ( class-based inheritance), retaining similar implementation. Also defined as deriving new class ...
s member variables are inherited by grandchild derived classes. Without virtual inheritance, if two classes 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 As 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
multiple inheritance Multiple inheritance is a feature of some object-oriented computer programming languages in which an object or class can inherit features from more than one parent object or parent class. It is distinct from single inheritance, where an object or ...
, 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 Multiple inheritance is a feature of some object-oriented computer programming languages in which an object or class can inherit features from more than one parent object or parent class. It is distinct from single inheritance, where an object ...
by clarifying ambiguity over which ancestor class to use, as from the perspective of the deriving class (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
keyword Keyword may refer to: Computing * Keyword (Internet search), a word or phrase typically used by bloggers or online content creator to rank a web page on a particular topic * Index term, a term used as a keyword to documents in an information syst ...
. Consider the following class hierarchy. struct Animal ; struct Mammal: Animal ; struct WingedAnimal: Animal ; // A bat is a winged mammal struct Bat: Mammal, WingedAnimal ; Bat bat; 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: Bat b; Animal& a = b; // error: which Animal subobject should a Bat cast into, // a Mammal::Animal or a WingedAnimal::Animal? To disambiguate, one would have to explicitly convert bat to either base class subobject: Bat b; Animal& mammal = static_cast(b); Animal& winged = static_cast(b); In order to call 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
Diamond problem Multiple inheritance is a feature of some object-oriented computer programming languages in which an object or class can inherit features from more than one parent object or parent class. It is distinct from single inheritance, where an object ...
) because the inheritance diagram is in the shape of a diamond. Virtual inheritance can help to solve this problem.


The solution

We can re-declare our classes as follows: struct Animal ; // Two classes virtually inheriting Animal: struct Mammal: virtual Animal ; struct WingedAnimal: virtual Animal ; // A bat is still a winged mammal struct Bat: Mammal, WingedAnimal ; The 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 vtable pointers, one per inheritance hierarchy that virtually inherits 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 class A has a constructor variable msg and an additional ancestor E is derived from grandchild class D.
  A  
 / \  
B   C  
 \ /  
  D 
  , 
  E
Here, 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 interactivel
here
#include #include class A ; // B,C inherit A virtually class B: virtual public A ; class C: virtual public A ; // Compile error when :A("c") is removed (since A's constructor is not called) //class C: virtual public A ; //class C: virtual public A ; // Same compile error // Since B, C inherit A virtually, A must be constructed in each child class D: public B,C ; class E: public D ; // Compile error without constructing A //class D: public B,C ; // Compile error without constructing A //class E: public D ; int main(int argc, char ** argv)


Pure 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 interactivel
here
#include #include class A ; // since B,C inherit A virtually, the pure virtual method pure_virtual_test doesn't need to be defined class B: virtual public A ; class C: virtual public A ; // since B,C inherit A virtually, A must be constructed in each child // however, since D does not inherit B,C virtually, the pure virtual method in A *must be defined* class D: public B,C ; // it is not necessary to redefine the pure virtual method after the parent defines it class E: public D ; int main(int argc, char ** argv)


References

{{C++ programming language Class (computer programming) C++ sv:Multipelt arv tr:Çoklu kalıtım