Multiple Inheritance
What is Multiple Inheritance?
So far, we have seen only single inheritance:

A reminder: the arrows in an inheritance diagram point from a derived class to its base class.
But a class may be derived from more than one base class:

Other examples might be:


From Tree to DAG
Note that multiple inheritance moves us away from a simple tree structure:

towards a Directed Acyclic Graph — the dreaded DAG, or diamond shape:

Example of Multiple Inheritance
A class indicates that it derives from more than one class by listing multiple classes in its inheritance list:
class ToyTruck : public Toy, public Truck
{
// ...
}
Here’s an example of an implementation of a ‘toy’ multiple inheritance hierarchy, consisting of classes Toy, Barbie, Truck, and ToyTruck:
//
// Toy.h
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#ifndef Toy_h
#define Toy_h
class Toy
{
public:
enum ToyType { Doll, ActionFigure, Vehicle };
Toy(ToyType type) : m_type(type) {}
ToyType GetType() const { return m_type; }
virtual void Print() const;
private:
ToyType m_type;
};
#endif /* Toy_h *///
// Toy.cpp
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Toy.h"
static std::string toyType[] =
{ "Doll", "Action figure", "Vehicle" };
void Toy::Print() const
{
std::cout << "Toy " << std::endl;
std::cout << " Toy type: " << toyType[m_type]
<< std::endl;
}//
// Barbie.h
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#ifndef Barbie_h
#define Barbie_h
#include "Toy.h"
// Barbie.h
class Barbie : public Toy
{
public:
enum HairColor { Blond, Brunette, Redhead };
Barbie(HairColor color)
: Toy(Doll), m_hairColor(color) {}
HairColor GetHairColor() { return m_hairColor; }
virtual void Print() const;
private:
HairColor m_hairColor;
};
#endif /* Barbie_h *///
// Barbie.cpp
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Barbie.h"
void Barbie::Print() const
{
static std::string hairType[] =
{ "Blond", "Brunette", "Redhead" };
Toy::Print();
std::cout << " Hair color: "
<< hairType[m_hairColor]
<< std::endl;
}//
// Truck.h
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#ifndef Truck_h
#define Truck_h
class Truck
{
public:
Truck(double hp, bool isFwd)
: m_hp(hp), m_is_fwd(isFwd) {}
double GetHorsePower() const { return m_hp; }
bool IsFourWheelDrive() const { return m_is_fwd; }
virtual void Print() const;
private:
double m_hp; // Horsepower
bool m_is_fwd; // Is 4-wheel drive
};
#endif /* Truck_h *///
// Truck.cpp
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Truck.h"
void Truck::Print() const
{
std::cout << "Truck:" << std::endl
<< " Horsepower: " << m_hp << std::endl
<< " Four wheel drive: "
<< ((m_is_fwd)? "Yes" : "No")
<< std::endl;
}//
// ToyTruck.h
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#ifndef ToyTruck_h
#define ToyTruck_h
#include "Toy.h"
#include "Truck.h"
class ToyTruck : public Toy, public Truck
{
public:
ToyTruck() : Toy(Vehicle), Truck(0, false) {}
virtual void Print() const;
};
#endif /* ToyTruck_h *///
// ToyTruck.cpp
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "ToyTruck.h"
void ToyTruck::Print() const
{
std::cout << "ToyTruck: " << std::endl;
Toy::Print();
Truck::Print();
}Here’s the main program:
//
// main.cpp
// Multiple Inheritance - Toy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Barbie.h"
#include "Truck.h"
#include "ToyTruck.h"
int main(int argc, const char * argv[])
{
Barbie barbie(Barbie::Blond);
Truck truck(450, true);
ToyTruck toyTruck;
std::cout << "barbie is ";
barbie.Print();
std::cout << "truck is ";
truck.Print();
std::cout << "toyTruck is ";
toyTruck.Print();
return 0;
}Which outputs:
barbie is Toy
Toy type: Doll
Hair color: Blond
truck is Truck:
Horsepower: 450
Four wheel drive: Yes
toyTruck is ToyTruck:
Toy
Toy type: Vehicle
Truck:
Horsepower: 0
Four wheel drive: No
Program ended with exit code: 0
Multiple Inheritance Concepts
The order of derivation is not important, except for constructor initialization, destructor cleanup, and possibly storage layout.
A class listed in the base class list is a direct base class of the derived class.
An indirect base class is one which is not a direct base class, but is a base class of one of the direct base classes.
Got that?
A direct base class may not be specified in the base class list more than once:
class X : public A, public B, public A // compile-time error
{
// ...
}However, a class may be an indirect base class more than once:
class A : { ... };
class B : public A { ... };
class C : public A { ... };
class X : public A, public B
{
// ...
};Multiple Inheritance and Constructors
The order of constructor execution is:
- Base class constructor(s), in declaration order (independent of initializer list order)
- Derived class member constructor(s), in declaration order (independent of initializer list order)
- The body of the derived class constructor.
Virtual base classes are a special case (see later).
Multiple Inheritance and Destructors
The order of destructor execution is:
- The body of the derived class destructor.
- Derived class member destructor(s), in reverse declaration order
- Base class destructor(s), in reverse declaration order
In other words, the exact opposite of constructor execution order.
Again, virtual base classes are a special case (see later).
Mixins
A common use of multiple inheritance is the addition of service protocols to class hierarchies:
class Person : public Persistant, public Sortable
{ ... };
class Shape : public Persistant, public Listable
{ ... };
This is called mixin inheritance — apparently from a common practice among ice cream stores of mixing candies, etc., into ice cream:
class Scoop : public Jimmies, public M_and_Ms
{ ... };
Member Access under Multiple Inheritance
Access to base class members must be unambiguous.
The check for ambiguity takes place before access control:
//
// main.cpp
// Multiple Inheritance - Ambiguous Member Access
//
// Created by Bryan Higgs on 8/30/24.
//
class One
{
public:
int i;
};
class Two
{
private:
int i;
};
class OneTwo : public One, public Two
{
// no additional members
};
int main(int argc, const char * argv[])
{
OneTwo ot;
ot.i = 10; // ERROR: ambiguous
ot.One::i = 11; // OK
ot.Two::i = 12; // ERROR: no access
return 0;
}main.cpp:28:6 Member 'i' found in multiple base classes of different types
main.cpp:30:11 'i' is a private member of 'Two'
Further Exploration
Let’s implement our Person / Student / Employee / TeachingAssistant example:
//
// Taxonomy.h
// Multiple Inheritance - Taxonomy
//
// Created by Bryan Higgs on 8/30/24.
//
#ifndef Taxonomy_h
#define Taxonomy_h
#include <string>
class Person
{
public:
Person(const std::string &name);
virtual ~Person();
const std::string &getName() const
{ return m_name; }
virtual void Print() const = 0;
private:
std::string m_name; // Person name
};
// class Student
class Student : public Person
{
public:
Student(const std::string &name, int id);
virtual ~Student();
const int GetId() const
{ return m_sid; }
const double GetGpa() const
{ return m_sgpa; }
void SetGpa(double gpa)
{ m_sgpa = gpa; }
virtual void Print() const;
private:
int m_sid; // Student ID
double m_sgpa; // Grade Point Average
};
// class Employee
class Employee : public Person
{
public:
Employee(const std::string &name, double salary);
virtual ~Employee();
double GetSalary() const { return m_salary; }
virtual void Print() const;
private:
double m_salary; // Employee salary
};
// class TeachingAssistant
class TeachingAssistant : public Student,
public Employee
{
public:
TeachingAssistant(const std::string &name,
int id, double salary);
virtual ~TeachingAssistant();
virtual void Print() const;
};
#endif /* Taxonomy_h */… and we instrument the constructors and destructors, in order to see what’s happening:
//
// Taxonomy.cpp
// Multiple Inheritance - Taxonomy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Taxonomy.h"
// class Person
Person::Person(const std::string &name)
: m_name(name)
{
std::cout << "In Person()" << std::endl;
}
Person::~Person()
{
std::cout << "In ~Person()" << std::endl;
}
void Person::Print() const
{
std::cout << "Name: " << m_name << std::endl;
}
// class Student
Student::Student(const std::string &name, int id)
: Person(name), m_sid(id), m_sgpa(0.0)
{
std::cout << "In Student()" << std::endl;
}
Student::~Student()
{
std::cout << "In ~Student()" << std::endl;
}
void Student::Print() const
{
Person::Print();
std::cout << "Id: " << m_sid << std::endl
<< "GPA: " << m_sgpa << std::endl;
}
// class Employee
Employee::Employee(const std::string &name, double salary)
: Person(name), m_salary(salary)
{
std::cout << "In Employee()" << std::endl;
}
Employee::~Employee()
{
std::cout << "In ~Employee()" << std::endl;
}
void Employee::Print() const
{
Person::Print();
std::cout << "Salary: " << m_salary << std::endl;
}
// class TeachingAssistant
TeachingAssistant::TeachingAssistant(const std::string &name,
int id, double salary)
: Student(name, id), Employee(name, salary)
{
std::cout << "In TeachingAssistant()" << std::endl;
}
TeachingAssistant::~TeachingAssistant()
{
std::cout << "In ~TeachingAssistant()" << std::endl;
}
void TeachingAssistant::Print() const
{
Student::Print();
Employee::Print();
}
Here’s a simple main program:
//
// main.cpp
// Multiple Inheritance - Taxonomy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Taxonomy.h"
int main(int argc, const char * argv[])
{
TeachingAssistant ta("Fred Bloggs",
57, 3000.00);
ta.Print();
return 0;
}… which produces the following output:
In Person()
In Student()
In Person()
In Employee()
In TeachingAssistant()
Name: Fred Bloggs
Id: 57
GPA: 0
Name: Fred Bloggs
Salary: 3000
In ~TeachingAssistant()
In ~Employee()
In ~Person()
In ~Student()
In ~Person()
Program ended with exit code: 0
Can you explain this?
What we wanted was a hierarchy like:

But what we actually have is a hierarchy like:

How do we fix this?
Virtual Base Classes
Because a class can be an indirect base class to a derived class more than once, C++ provides a way to optimize the way such base classes work. Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that use multiple inheritance.
Each nonvirtual object contains a copy of the data members defined in the base class. This duplication wastes space and requires you to specify which copy of the base class members you want whenever you access them.
When a base class is specified as a virtual base, it can act as an indirect base more than once without duplication of its data members. A single copy of its data members is shared by all the base classes that use it as a virtual base.
When declaring a virtual base class, the virtual keyword appears in the base lists of the derived classes.
To user virtual base classes in our example, we make the following changes:
//
// Taxonomy.h
// Multiple Inheritance - Taxonomy
//
// Created by Bryan Higgs on 8/30/24.
//
#ifndef Taxonomy_h
#define Taxonomy_h
#include <string>
class Person
{
public:
Person(const std::string &name);
virtual ~Person();
const std::string &getName() const
{ return m_name; }
virtual void Print() const = 0;
private:
std::string m_name; // Person name
};
// class Student
class Student : public virtual Person
{
public:
Student(const std::string &name, int id);
virtual ~Student();
const int GetId() const
{ return m_sid; }
const double GetGpa() const
{ return m_sgpa; }
void SetGpa(double gpa)
{ m_sgpa = gpa; }
virtual void Print() const;
private:
int m_sid; // Student ID
double m_sgpa; // Grade Point Average
};
// class Employee
class Employee : public virtual Person
{
public:
Employee(const std::string &name, double salary);
virtual ~Employee();
double GetSalary() const { return m_salary; }
virtual void Print() const;
private:
double m_salary; // Employee salary
};
// class TeachingAssistant
class TeachingAssistant : public Student,
public Employee
{
public:
TeachingAssistant(const std::string &name,
int id, double salary);
virtual ~TeachingAssistant();
virtual void Print() const;
};
#endif /* Taxonomy_h */… and also make changes here:
//
// Taxonomy.cpp
// Multiple Inheritance - Taxonomy
//
// Created by Bryan Higgs on 8/30/24.
//
#include <iostream>
#include "Taxonomy.h"
// class Person
Person::Person(const std::string &name)
: m_name(name)
{
std::cout << "In Person()" << std::endl;
}
Person::~Person()
{
std::cout << "In ~Person()" << std::endl;
}
void Person::Print() const
{
std::cout << "Name: " << m_name << std::endl;
}
// class Student
Student::Student(const std::string &name, int id)
: Person(name), m_sid(id), m_sgpa(0.0)
{
std::cout << "In Student()" << std::endl;
}
Student::~Student()
{
std::cout << "In ~Student()" << std::endl;
}
void Student::Print() const
{
// Person::Print(); - Removed
std::cout << "Id: " << m_sid << std::endl
<< "GPA: " << m_sgpa << std::endl;
}
// class Employee
Employee::Employee(const std::string &name, double salary)
: Person(name), m_salary(salary)
{
std::cout << "In Employee()" << std::endl;
}
Employee::~Employee()
{
std::cout << "In ~Employee()" << std::endl;
}
void Employee::Print() const
{
// Person::Print(); - Removed
std::cout << "Salary: " << m_salary << std::endl;
}
// class TeachingAssistant
TeachingAssistant::TeachingAssistant(const std::string &name,
int id, double salary)
: Person(name), // Added
Student(name, id), Employee(name, salary)
{
std::cout << "In TeachingAssistant()" << std::endl;
}
TeachingAssistant::~TeachingAssistant()
{
std::cout << "In ~TeachingAssistant()" << std::endl;
}
void TeachingAssistant::Print() const
{
Person::Print(); // Added
Student::Print();
Employee::Print();
}With no further changes, the exact same main program produces:
In Person()
In Student()
In Employee()
In TeachingAssistant()
Name: Fred Bloggs
Id: 57
GPA: 0
Salary: 3000
In ~TeachingAssistant()
In ~Employee()
In ~Student()
In ~Person()
Program ended with exit code: 0
Points to note:
The virtualness of Person is a property of the derivation, not a property of Person itself.
A class may be both an ordinary class and a virtual base in the same inheritance hierarchy.
One may cast from a derived class to a virtual base class, but not from a virtual base class to a derived class.
Constructors and Virtual Base Classes
Constructors for virtual base classes are a special case:
- Virtual bases are constructed before any non-virtual classes.
- Virtual bases are constructed in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes.
- ‘Left-to-right’ is the order of appearance of the base class names in the declaration of the derived class.
- If a virtual base class does not have a default constructor, it must be explicitly initialized by every derived class.
Destructors and Virtual Base Classes
Destructors for virtual base classes are called in the reverse order of their appearance in a directed acyclic graph (depth-first, left-to-right, postorder traversal).
This area of C++ is definitely arcane!
The Complexities of Multiple Inheritance
Multiple inheritance is much more complex than single inheritance.
- There is one case where multiple inheritance is simple: when inheriting from disjoint base classes — for example, adding mixins.
- Even in the simple case, there is the possibility of name conflicts among the base class members.
- When a common single instance of a base class is desired, it is necessary to use virtual base classes — which introduces more complexity.
Bottom Line: Avoid Multiple Inheritance as far as possible. It’s a quagmire!