In C++, class hierarchies can lead to the diamond problem, where two subclasses inherit from the same base class, and then another class inherits from those two. In this case, an object of the derived class will contain two independent copies of the base class. To solve this problem, C++ implements virtual inheritance.
If regular multiple inheritance is used:
class A { public: int x; }; class B : public A {}; class C : public A {}; class D : public B, public C {};
Object D will contain 2 copies of A: one through B, another through C. This causes ambiguity in accessing A::x and unnecessary memory usage.
Virtual inheritance eliminates the duplication of the base class. One instance of the base class A will be used by all descendants:
class A { public: int x; }; class B : public virtual A {}; class C : public virtual A {}; class D : public B, public C {};
Now D contains only one copy of A, and the ambiguity in accessing A::x is resolved.
Key features:
Why can't the diamond problem be solved using explicit path specification with scope resolution?
Scope resolution only resolves the ambiguity in accessing members of the base class but does not eliminate the extra copies of the base class itself. The problem of double initialization and double storage of data remains.
In what order are constructors called in virtual inheritance?
Constructors of virtual base classes are called first and only once, directly by the constructor of the last class in the inheritance hierarchy.
Example:
class A { public: A() { std::cout << "A "; } }; class B : public virtual A { public: B() { std::cout << "B "; } }; class C : public virtual A { public: C() { std::cout << "C "; } }; class D : public B, public C { public: D() { std::cout << "D "; } }; D d; // Output: A B C D
Is it mandatory to declare virtual inheritance both when declaring and defining the class?
Yes, virtual inheritance must be specified everywhere inheritance from the corresponding base class occurs. Otherwise, a compilation error is inevitable, and multiple inheritance will become ordinary.
A complex hierarchy where virtual inheritance is not applied, resulting in two copies of settings in the object:
Pros:
Cons:
Virtual inheritance is used with a consistent constructor of the topmost descendant:
Pros:
Cons: