Multiple inheritance allows a class to inherit the interface and implementation of more than one base class. This is a powerful feature of C++, which has been widely used since the early days of the language to implement complex architectures.
Background: Multiple inheritance was added to C++ as a means of creating reusable components and combining different roles in one class (for example, when an object is both a thread and a queue).
Problem: The main challenges with multiple inheritance are the 'diamond problem', ambiguity when accessing members of base classes, and the unclear order of constructor/destructor calls.
Solution: To avoid these issues, C++ provides virtual inheritance. It ensures that a common ancestor is created only once, even if multiple chains lead to it in the hierarchy, and it ensures the correct order of initialization/destruction.
Example code:
class A { public: int value; A() : value(1) {} }; class B : virtual public A {}; class C : virtual public A {}; class D : public B, public C {}; int main() { D d; d.value = 10; // OK, only one A return 0; }
Key features:
If a base class is inherited twice (from left and right), how many copies of this class will be in the object's memory?
By default, two, unless virtual inheritance is used. Only with virtual inheritance will there be exactly one copy.
Can you explicitly specify which base class a member refers to when ambiguity arises?
Yes, using qualifiers:
d.B::value = 5; d.C::value = 6;
How is the order of constructors and destructors determined in multiple inheritance?
The order of constructor calls corresponds to the order of declaration of base classes in the inheritance list (left to right), and then the derived class itself. For destructors, it is the reverse.
A programmer implements a logging and queuing system through multiple inheritance, unaware of the diamond problem. As a result, the common logger is initialized twice, leading to a conflict when releasing resources.
Pros:
Cons:
Virtual inheritance is used for the common logger, and class members are explicitly initialized in the constructor.
Pros:
Cons: