{{Short description|Technique in the C++ language}} {{For|inheritance of virtual functions|virtual function}} [[File:Diamond inheritance.svg|thumb|Diagram of diamond inheritance, a problem that virtual inheritance is trying to solve.]] '''Virtual inheritance''' is a C++ technique that ensures only one copy of a base class{{'}}s member variables are inherited by grandchild derived classes. Without virtual inheritance, if two classes <code>B</code> and <code>C</code> inherit from a class <code>A</code>, and a class <code>D</code> inherits from both <code>B</code> and <code>C</code>, then <code>D</code> will contain two copies of <code>A</code>{{'}}s member variables: one via <code>B</code>, and one via <code>C</code>. These will be accessible independently, using scope resolution.
Instead, if classes <code>B</code> and <code>C</code> inherit virtually from class <code>A</code>, then objects of class <code>D</code> will contain only one set of the member variables from class <code>A</code>.
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 (<code>D</code> in the example above) the virtual base (<code>A</code>) acts as though it were the direct base class of <code>D</code>, not a class derived indirectly through a base (<code>B</code> or <code>C</code>).<ref>{{cite web | access-date = 2010-03-08 | website = Cprogramming.com | title = Solving the Diamond Problem with Virtual Inheritance | first = Andrei | last = Milea | url = http://www.cprogramming.com/tutorial/virtual_inheritance.html | quote = One of the problems that arises due to multiple inheritance is the diamond problem. A classical illustration of this is given by Bjarne Stroustrup (the creator of C++) in the following example: }}</ref><ref>{{cite web |access-date = 2010-03-08 |website = All Experts |title = C++/What is virtual inheritance? |first = Ralph |last = McArdell |date = 2004-02-14 |url = http://en.allexperts.com/q/C-1040/virtual-inheritance.htm |quote = This is something you find may be required if you are using multiple inheritance. In that case it is possible for a class to be derived from other classes which have the same base class. In such cases, without virtual inheritance, your objects will contain more than one subobject of the base type the base classes share. Whether this is what is the required effect depends on the circumstances. If it is not then you can use virtual inheritance by specifying virtual base classes for those base types for which a whole object should only contain one such base class subobject. |archive-url = https://web.archive.org/web/20100110180819/http://en.allexperts.com/q/C-1040/virtual-inheritance.htm |archive-date = 2010-01-10 |url-status = dead }}</ref>
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 <code>virtual</code> keyword.
Consider the following class hierarchy.
UML virtual inheritance.svg
<syntaxhighlight lang="cpp"> class Animal { public: virtual ~Animal() = default; // Explicitly show that the default class destructor will be made. virtual void eat() {} };
class Mammal: public Animal { public: virtual void breathe() {} };
class WingedAnimal: public Animal { public: virtual void flap() {} };
// A bat is a winged mammal class Bat: public Mammal, public WingedAnimal {}; </syntaxhighlight> As declared above, a call to <code>bat.eat()</code> is ambiguous because there are two <code>Animal</code> (indirect) base classes in <code>Bat</code>, so any <code>Bat</code> object has two different <code>Animal</code> base class subobjects. So, an attempt to directly bind a reference to the <code>Animal</code> subobject of a <code>Bat</code> object would fail, since the binding is inherently ambiguous: <syntaxhighlight lang="cpp"> Bat bat; Animal& animal = bat; // error: which Animal subobject should a Bat cast into, // a Mammal::Animal or a WingedAnimal::Animal? </syntaxhighlight>
To disambiguate, one would have to explicitly convert <code>bat</code> to either base class subobject: <syntaxhighlight lang="cpp"> Bat bat; Animal& mammal = static_cast<Mammal&>(bat); Animal& winged = static_cast<WingedAnimal&>(bat); </syntaxhighlight>
In order to call <code>eat()</code>, the same disambiguation, or explicit qualification is needed: <code>static_cast<Mammal&>(bat).eat()</code> or <code>static_cast<WingedAnimal&>(bat).eat()</code> or alternatively <code>bat.Mammal::eat()</code> and <code>bat.WingedAnimal::eat()</code>. 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 <code>Animal</code> is probably unwanted, as we want to model that the relation (<code>Bat</code> is an <code>Animal</code>) exists only once; that a <code>Bat</code> is a <code>Mammal</code> and is a <code>WingedAnimal</code>, does not imply that it is an <code>Animal</code> twice: an <code>Animal</code> base class corresponds to a contract that <code>Bat</code> implements (the "is a" relationship above really means "''implements the requirements of''"), and a <code>Bat</code> only implements the <code>Animal</code> contract once. The real world meaning of "''is a'' only once" is that <code>Bat</code> should have only one way of implementing <code>Eat</code>, not two different ways, depending on whether the <code>Mammal</code> view of the <code>Bat</code> is eating, or the <code>WingedAnimal</code> view of the <code>Bat</code>. (In the first code example we see that <code>Eat</code> is not overridden in either <code>Mammal</code> or <code>WingedAnimal</code>, so the two <code>Animal</code> 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) 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: <syntaxhighlight lang="cpp"> class Animal { public: virtual ~Animal() = default; virtual void eat() {} };
// Two classes virtually inheriting Animal: class Mammal: virtual public Animal { public: virtual void breathe() {} };
class WingedAnimal: virtual public Animal { public: virtual void flap() {} };
// A bat is still a winged mammal class Bat: public Mammal, public WingedAnimal {}; </syntaxhighlight> The <code>Animal</code> portion of <code>Bat::WingedAnimal</code> is now the ''same'' <code>Animal</code> instance as the one used by <code>Bat::Mammal</code>, which is to say that a <code>Bat</code> has only one, shared, <code>Animal</code> instance in its representation and so a call to <code>Bat::Eat</code> is unambiguous. Additionally, a direct cast from <code>Bat</code> to <code>Animal</code> is also unambiguous, now that there exists only one <code>Animal</code> instance which <code>Bat</code> could be converted to.
The ability to share a single instance of the <code>Animal</code> parent between <code>Mammal</code> and <code>WingedAnimal</code> is enabled by recording the memory offset between the <code>Mammal</code> or <code>WingedAnimal</code> members and those of the base <code>Animal</code> within the derived class. However this offset can in the general case only be known at runtime, thus <code>Bat</code> must become (<code>vpointer</code>, <code>Mammal</code>, <code>vpointer</code>, <code>WingedAnimal</code>, <code>Bat</code>, <code>Animal</code>). There are two vtable pointers, one per inheritance hierarchy that virtually inherits <code>Animal</code>. In this example, one for <code>Mammal</code> and one for <code>WingedAnimal</code>. The object size has therefore increased by two pointers, but now there is only one <code>Animal</code> and no ambiguity. All objects of type <code>Bat</code> will use the same vpointers, but each <code>Bat</code> object will contain its own unique <code>Animal</code> object. If another class inherits from <code>Mammal</code>, such as <code>Squirrel</code>, then the vpointer in the <code>Mammal</code> part of <code>Squirrel</code> will generally be different to the vpointer in the <code>Mammal</code> part of <code>Bat</code> though they may happen to be the same if the <code>Squirrel</code> class is the same size as <code>Bat</code>.
=== Additional Example of Several Ancestors === This example to illustrates a case where base class <code>A</code> has a constructor variable <code>msg</code> and an additional ancestor <code>E</code> is derived from grandchild class <code>D</code>. <pre> A / \ B C \ / D | E </pre> Here, <code>A</code> must be constructed in both <code>D</code> and <code>E</code>. Further, inspection of the variable <code>msg</code> illustrates how class <code>A</code> becomes a direct base class of its deriving class, as opposed to a base class of any intermediate deriving classed between <code>A</code> and the final deriving class. <syntaxhighlight lang="c++"> import std;
using std::string;
class A { private: string msg; public: explicit A(const string& s): msg{s} {}
void test() { std::println("Hello from A: {}", msg); } };
// B, C inherit A virtually class B: virtual public A { public: B(): A("instance of B") {} };
class C: virtual public A { public: C(): A("instance of C") {} };
// since B, C inherit A virtually, A must be constructed in each child // B() and C() constructors can be omitted class D: public B, public C { public: D(): A("instance of D"), B(), C() {} };
// D() constructor can be omitted class E: public D { public: E(): A("instance of E"), D() {} };
// breaks without constructing A: // class D: public B, public C { // public: // D(): // B(), C() {} // };
// breaks without constructing A // class E: public D { // public: // E(): // D() {} // };
int main(int argc, char* argv[]) { D d; d.test(); // prints: "hello from A: instance of D"
E e; e.test(); // prints: "hello from A: instance of E" } </syntaxhighlight>
==== 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. <syntaxhighlight lang="c++"> import std;
using std::string;
class A { protected: string msg; public: explicit A(const string& s): msg{s} {}
void test() { std::println("Hello from A: {}", msg); } virtual void pureVirtualTest() = 0; };
// since B, C inherit A virtually, the pure virtual method pureVirtualTest doesn't need to be defined class B: virtual public A { public: explicit B(maybe_unused const string& s = ""): A("instance of B") {} };
class C: virtual public A { public: explicit C(maybe_unused const string& s = ""): A("instance of C") {} };
// 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, public C { public: explicit D(maybe_unused const string& s = ""): A("instance of D from constructor A"), B("instance of D from constructor B"), C("instance of D from constructor C") {}
void pureVirtualTest() override { std::println("Pure virtual hello from: {}", msg); } };
// it is not necessary to redefine the pure virtual method after the parent defines it class E: public D { public: explicit E(maybe_unused const string& s = ""): A("instance of E from constructor A"), D("instance of E from constructor D") {} };
int main(int argc, char* argv[]) { D d("d"); d.test(); // Hello from A: instance of D from constructor A d.pureVirtualTest(); // Pure virtual hello from: instance of D from constructor A
E e("e"); e.test(); // Hello from A: instance of E from constructor A e.pureVirtualTest(); // Pure virtual hello from: instance of E from constructor A } </syntaxhighlight>
==References== {{reflist}}
{{C++ programming language}}
Category:Class (computer programming) Category:C++