Multiple Inheritance
Learn how to inherit from multiple base classes and handle the diamond problem
Learn how to inherit from multiple base classes to model objects that exhibit characteristics of multiple types, and how to resolve the diamond problem.
A Simple Example
#include <iostream>
#include <string>
class Flyer {
protected:
int altitude;
public:
Flyer() : altitude{0} {
std::cout << "Flyer constructor" << "\n";
}
void takeOff() {
altitude = 100;
std::cout << "Taking off to altitude " << altitude << "\n";
}
void land() {
altitude = 0;
std::cout << "Landing" << "\n";
}
};
class Swimmer {
protected:
int depth;
public:
Swimmer() : depth{0} {
std::cout << "Swimmer constructor" << "\n";
}
void dive() {
depth = 50;
std::cout << "Diving to depth " << depth << "\n";
}
void surface() {
depth = 0;
std::cout << "Surfacing" << "\n";
}
};
class Duck : public Flyer, public Swimmer {
private:
std::string name;
public:
Duck(std::string name) : name{name} {
std::cout << "Duck " << name << " created" << "\n";
}
void display() {
std::cout << name << " - Altitude: " << altitude << ", Depth: " << depth << "\n";
}
void migrate() {
std::cout << name << " is migrating..." << "\n";
takeOff();
land();
dive();
surface();
}
};
int main() {
Duck mallard{"Mallard"};
mallard.display();
std::cout << "\nMigration time:" << "\n";
mallard.migrate();
mallard.display();
return 0;
}
Breaking It Down
Multiple Inheritance Syntax
-
Syntax:
class Derived : public Base1, public Base2 { }; - Separate base classes with commas
- Each base can have its own access specifier (public, protected, private)
- Remember: Constructor initialization list calls base constructors left-to-right
Member Access and Ambiguity
- Derived class has ALL members from ALL base classes
-
If two bases have same-named members, use scope resolution:
Base1::member -
Example: If both have
display(), callBase1::display()orBase2::display() - Remember: Compiler won't guess which one you want - you must specify
Constructor and Destructor Order
- Construction: Base classes constructed left-to-right, then derived class
- Destruction: Opposite order - derived first, then bases right-to-left
-
Example:
Duck : Flyer, Swimmerconstructs Flyer, then Swimmer, then Duck - Remember: Same order rules as single inheritance, just with multiple bases
When to Use Multiple Inheritance
- Use for "is-a" relationships with multiple types (Duck IS-A Flyer AND IS-A Swimmer)
- Prefer composition over multiple inheritance when possible
- Common use: Combining interfaces (pure virtual base classes)
- Remember: Multiple inheritance is powerful but complex - use sparingly
Why This Matters
- Sometimes an object genuinely exhibits characteristics of multiple types. An amphibious vehicle is both a Boat and a Car. A teaching assistant is both a Student and an Employee.
- Multiple inheritance lets you model these relationships directly. However, it's a double-edged sword - powerful but complex.
- Understanding multiple inheritance helps you use it wisely when appropriate, and avoid it when composition would be better. It's controversial in software design, so knowing when and how to use it is a mark of a skilled developer.
Critical Insight
The famous "Diamond Problem" occurs when two base classes inherit from the same grandparent, creating two copies of the grandparent's members. Virtual inheritance solves this by ensuring only one copy exists:
class Animal {
public:
std::string name;
};
// Without virtual inheritance - BAD
class Bird : public Animal { };
class Fish : public Animal { };
class Duck : public Bird, public Fish { };
// Duck has TWO copies of name - ambiguous!
// With virtual inheritance - GOOD
class Bird : public virtual Animal { };
class Fish : public virtual Animal { };
class Duck : public Bird, public Fish { };
// Duck has ONE copy of name - clear!
Best Practices
Prefer composition over multiple inheritance: Often, having member objects is clearer than inheriting from multiple bases.
Use virtual inheritance for diamond problem: When needed, use class Derived : virtual public Base.
Keep hierarchies shallow: Deep multiple inheritance hierarchies are hard to understand and maintain.
Document relationships clearly: Explain why multiple inheritance is needed and how ambiguities are resolved.
Common Mistakes
Ambiguous member access: When both base classes have members with the same name, you must specify which one.
Diamond problem without virtual inheritance: Inheriting from two classes that share a common base creates duplicate members.
Constructor initialization order: Base class constructors must be explicitly called in the order they appear in the inheritance list.
Increased complexity: Multiple inheritance makes code harder to understand and debug - use only when necessary.
Debug Challenge
This code has an ambiguity problem. Click the highlighted line to fix it:
Quick Quiz
- What syntax is used for multiple inheritance?
- What is the diamond problem?
- How do you resolve ambiguity when both bases have a method
foo()?
Practice Playground
Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.
Output:
Error:
Lesson Progress
- Fix This Code
- Quick Quiz
- Practice Playground - run once