Multiple Inheritance
Lesson outline
Concept & Appropriate Use Cases
Multiple inheritance allows a class to derive from multiple base classes simultaneously. This is particularly useful for:
- Implementing interfaces (pure abstract classes)
- Combining orthogonal functionalities
- Mixin-based development
- Simulating traits or aspects
A classic example is a 'FlyingCar' inheriting from both 'Car' and 'Aircraft'.
The Diamond Problem & Virtual Inheritance
When two parent classes inherit from the same grandparent, a derived class may contain duplicate grandparent subobjects (the diamond). Virtual inheritance ensures there is only one shared subobject of the virtual base.
Consider this hierarchy:
Person
/ \
Employee Student
\ /
TeachingAssistant
With virtual inheritance, the most-derived class is responsible for constructing the virtual base.
Method Resolution Order
In multiple inheritance, name lookup considers all base classes. If a non-virtual member with the same name exists in multiple bases, an unqualified call is ambiguous and must be disambiguated.
Key points:
- Base class subobjects are initialized left-to-right as listed in the inheritance list.
- For non-virtual members with the same name in different bases, use qualified calls (e.g., A::f(), B::f()).
- For virtual functions, dynamic dispatch calls the most-derived override; ambiguity arises only when the compiler cannot pick a single candidate at compile time.
Practical Patterns
- Interface Segregation: Inherit from multiple abstract interfaces
- Mixin Pattern: Small classes adding specific behaviors
- Policy-Based Design: Template parameters as compile-time alternatives
- Decorator Pattern: Prefer composition for layering behavior
- CRTP: Static polymorphism without virtual functions
Best Practices Summary
| Do | Don't |
|---|---|
| Use for interface implementation | Use for implementation inheritance across many concrete bases |
| Keep inheritance lists short (<3) | Create complex diamond hierarchies unnecessarily |
| Make interfaces pure abstract | Combine unrelated responsibilities in one type |
| Document the design and construction rules | Assume relationships are self-evident |
| Consider composition first | Default to multiple inheritance by habit |