Intermediate 13 min

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(), call Base1::display() or Base2::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, Swimmer constructs 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:

1 class A {
2 public:
3 void show() { std::cout << "A"; }
4 };
5
6 class B {
7 public:
8 void show() { std::cout << "B"; }
9 };
10
11 class C : public A, public B { };
12
13 int main() {
14 C obj;
15 obj.show();
16 }

Quick Quiz

  1. What syntax is used for multiple inheritance?
`class D : public Base1, public Base2 { };`
`class D : Base1 + Base2 { };`
`class D : public Base1 and Base2 { };`
  1. What is the diamond problem?
When two bases inherit from the same grandparent, creating duplicate members
A compiler error
When a class has four base classes
  1. How do you resolve ambiguity when both bases have a method foo()?
Use `Base1::foo()` or `Base2::foo()`
Can't be done
Automatically resolved

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.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once