Select Page

A C++ programmer strives for readable and reusable code. Easy-to-read code saves time and effort when making changes. Modifying such code will be easier for another developer jumping in.

C++ programmers use multiple inheritance to structure their code. Multiple inheritance lets you minimize copy-and-paste and improve overall conciseness. In this article, we’ll look at how multiple inheritance works, as well as what issues can arise and how to solve them.

What Is Multiple Inheritance in C++?

Inheritance is a fundamental programming concept and a critical feature of C++ polymorphism, which refers to a function or object’s ability to perform in multiple ways. The ability of one class to inherit the properties of another is referred to as inheritance.

There is a “parent” class and a “child” class in a simple inheritance relationship. During the declaration of the child class, the parent class’s methods and variables are automatically propagated to the child class. This eliminates the need for copy-paste and rewriting code.

Multiple inheritance is where a child class inherits from more than one parent. The goal of multiple inheritance is to allow multiple parent classes to share their characteristics with a single child.

How Does Multiple Inheritance Work?

Let’s say we want to create a program that provides information about a car. We’ll have two parent classes, SportsCar and CollectableObject, and a child class, called Ferrari, which will inherit the parents’ characteristics.

First, we create the two classes SportsCar and CollectableObject. Each contains a method that confirms that outputs a bit of text.

...class SportsCar // this class contains a method that confirms it is a sports car
{
public:
   
void infoSportsCar(string carModel)
{
    cout << "The " << carModel << " is a sports car." << endl;
} 
};

class CollectableObject // this class contains a method that confirms it is a collectable object
{
public:
   
void infoCollectableObject(string carModel)
{
    cout << "The " << carModel << " is a collectable object." << endl;
}
 
};...


Then, we create the class Ferrari that inherits from both the classes SportsCar and CollectableObject:

class Ferrari: public SportsCar, public CollectableObject //This class inherits the methods of the previous classes
{
public:
   
string model;
   
void infoFerrari(string carModel)
{
    cout << "This " << carModel << " is an amazing car!" << endl;
}

};


We want to display information about a certain Ferrari model. First, we create an object called myCar from the Ferrari class. We then call the methods of the Ferrari class and its parent classes, passing a model name as a parameter:

int main()
{
Ferrari myCar; //This object, created from the class Ferrari has got all the characteristics of CollectableObject and SportsCar
myCar.model = "1954 Ferrari 250 Monza";
myCar.infoSportsCar(myCar.model);
myCar.infoCollectableObject(myCar.model);
myCar.infoFerrari(myCar.model);
}

When we run the program, we get the following output:

The 1954 Ferrari 250 Monza is a sports car. 
The 1954 Ferrari 250 Monza is a collectable object. 
This 1954 Ferrari 250 Monza is an amazing car!

The program returned the values using the methods initially declared in the CollectableObject and SportsCar classes.

If you wanted to create a Bugatti class in the future, you could easily reuse the CollectableObject and SportsCar classes. They’d be parents to the new Bugatti class which would inherit all their characteristics.

Visibility Mode Implementation

In our example, you probably saw that we used the keyword public to define the methods within the classes. In C++, class members possess three visibility modes: public, private, and protected. We use these to assign a specific level of protection to class members and prevent misuse where needed.

  • The public attribute: objects and methods from the same class and from the outside, including the main function and other classes can call a public member.
  • The private attribute: only methods within the same class and a derived object can use a private element.
  • The protected attribute: only members within its class or  child classes can call it.

By default C++ defines class members as private if no attribute is specified. So, if you want a child class to use its parent’s methods, you need to declare them as public or protected

Let’s say our program now deals with a certain type of car, which we’ll call the “F” type. Each “F” type car has a unique engine number and a unique body number. You would not want these numbers to be altered, and you would only want a child class of engine or body to use them. Here’s how we would implement these requirements:

...class Engine
{
private:  // The variable below can't be altered from outside the class
   
int engineNumber = 9215;
   
protected: // The method below can only be accessed by a child of Engine
   
int vehicleEngineNumber()
{
    return engineNumber;
}
 
};

class Body
{
private: // The variable below can't be altered from outside the class
   
int bodyNumber = 37265;
   
protected: // The method below can only be accessed by a child of Body
   
int vehicleBodyNumber()
{
    return bodyNumber;
}
};...

First, we’ll create two classes similar to the previous ones, but with a private member (a serial number) and a protected member to be accessed by the Car class:

...class Car: public Engine, public Body
{
public:
string carCode;      string model;
int getBodyNb()
{
    int carBodyNb = vehicleBodyNumber();
    return carBodyNb;
}
   
int getEngineNb()
{
    int carEngineNb = vehicle_engine_number();
    return carEngineNb;
}
};...

The Car class declares a car code and two functions to get the engine and body numbers. The members of the Car class remain public so that we can call its functions from anywhere else:

...int main()
{
Car ferrari;
ferrari.model = "Ferrari F430";
ferrari.carCode = "fri";
   
cout << "This " << ferrari.model << " id number is: " <<      
      ferrari.getEngineNb() << endl <<
ferrari.getBodyNb() << ferrari.carCode;
}

The main function creates a ferrari object of the Car class. The ferrari object can now only call the functions in the Car class, as the functions from Engine and Body are not accessible to the ferrari object.

This Ferrari F430 id number is: 921537265fri


This example demonstrates how visibility mode works together with multiple inheritance. Combined, these features prevent unwanted modifications in the code.


If someone wanted to change the engine number for a given “F” type car, they would have to change it in the Engine class. But this would impact the child classes of Engine. The outside developer would think twice before making the change, and try to understand why this visibility mode was implemented in the first place.

The Diamond Problem

While multiple inheritance is useful, you might encounter scenarios where the compiler will throw an ambiguity error. Consider the following program: 

...class SteelComponent
{
public:
float steelPrice = 1.5;
};
class MotorPoweredVehicle: public SteelComponent
{
public:
   
float enginePrice = steelPrice * 380;
};

class WheeledVehicle: public SteelComponent
{
public:
   
float wheelPrice = steelPrice * 500;
};

class Car: public MotorPoweredVehicle, public WheeledVehicle
{
public:
string model;
float carSteelCost;
};...


Our MotorPoweredVehicle and WheeledVehicle classes are still parents of the Car class, but this time they are also children of the SteelComponent class because they are made from steel.

In other words, the Car class inherits the public variable of the SteelComponent class twice. Here’s what happens when the main function attempts to display the cost of steel:

int main()
{
Car opel;
opel.model = "Opel Corsa";
opel.carSteelCost = opel.wheelPrice + opel.enginePrice;

cout << "Total price for steel was: $" << opel.carSteelCost;
cout << " and the steel price was $" << opel.steelPrice << "/kg";
}


We get the following error:

main.cpp:37:50: error: request for member ‘steelPrice’ is ambiguous     cout << " and the steel price was $" << opel.steelPrice << "/kg";                                                  ^~~~~~~~~~main.cpp:8:24: note: candidates are: float SteelComponent::steelPrice     float steelPrice = 1.5;                        ^~~main.cpp:8:24: note:                 float SteelComponent::steelPrice

The compiler does not know which steelPrice candidate to use. To solve this problem, we have two options: the scope resolution operator and visual inheritance.

Scope Resolution Operator

You can use the scope resolution operator to tell the compiler where to look for the right class member. From our previous example, simply replace the last cout of the main function as follows:

...cout << " and the steel price was $" << opel.MotorPoweredVehicle::steelPrice << "/kg";...

When you add the word body and the double colon to specify where to pick up the information, you get the following output:

Total price for steel was: $1320 and the steel price was $1.5/kg

The compiler no longer throws an error, since it knows where to look for the data you requested.

Virtual Inheritance

Another way of solving the diamond problem is to prevent multiple copies of a base class, in our case, the steel class. When declaring the engine and body classes, simply add the keyword virtual in front of the parent class name:

...
class MotorPoweredVehicle: virtual public SteelComponent
...
class WheeledVehicle: virtual public SteelComponent...

The keyword virtual prevents the program from creating multiple copies of the steel class. You can now use the original syntax of cout, and the program will run perfectly.

Become a C++ Developer

You can leverage multiple inheritance to write professional, concise code that anyone who jumps into your program can understand. The various visibility modes assist you in limiting modifications and securing your code. You can avoid common issues like the diamond problem by properly implementing the scope resolution operator or virtual inheritance.

To take your C++ game to the next level, check out Udacity’s online program that’s designed to turn you into a C++ developer. All you need is intermediate knowledge of any programming language.

Enroll in our C++ Nanodegree program today!

Complete Code Examples

Example 1: Multiple Inheritance

#include <iostream>
#include <string>
using namespace std;

class SportsCar // this class contains a method that confirms it is a sports car
{
 public:
    
 void infoSportsCar(string carModel)
 {
    cout << "The " << carModel << " is a sports car." << endl;
 }  
};

class CollectableObject // this class contains a method that confirms it is a collectable object
{
 public:
    
 void infoCollectableObject(string carModel)
 {
     cout << "The " << carModel << " is a collectable object." << endl;
 }
   
};

class Ferrari: public SportsCar, public CollectableObject //This class inherits the methods of the previous classes
{
 public:
    
 string model;
    
 void infoFerrari(string carModel)
 {
    cout << "This " << carModel << " is an amazing car!" << endl;
 }
 
};

int main()
{
 Ferrari myCar; //This object, created from the class Ferrari has got all the characteristics of CollectableObject and SportsCar
 myCar.model = "1954 Ferrari 250 Monza";
 myCar.infoSportsCar(myCar.model);
 myCar.infoCollectableObject(myCar.model);
 myCar.infoFerrari(myCar.model);
}

Example 2: Visibility Mode

#include <iostream>
#include <string>
using namespace std;

class Engine
{
private:  // The variable below can't be altered from outside the class
   
int engineNumber = 9215;
   
protected: // The method below can only be accessed by a child of Engine
   
int vehicleEngineNumber()
{
    return engineNumber;
}
 
};

class Body
{
private: // The variable below can't be altered from outside the class
   
int bodyNumber = 37265;
   
protected: // The method below can only be accessed by a child of Body
   
int vehicleBodyNumber()
{
    return bodyNumber;
}
};
class Car: public Engine, public Body
{
public:
string carCode;
  string model;
int getBodyNb()
{
    int carBodyNb = vehicleBodyNumber();
    return carBodyNb;
}
   
int getEngineNb()
{
    int carEngineNb = vehicleEngineNumber();
    return carEngineNb;
}
};
int main()
{
Car ferrari;
ferrari.model = "Ferrari F430";
ferrari.carCode = "fri";
   
cout << "This " << ferrari.model << " id number is: " << 
  ferrari.getEngineNb() << endl <<
ferrari.getBodyNb() << ferrari.carCode;
}

Exemple 3 : Diamond Problem

#include <iostream>
#include <string>
using namespace std;

class SteelComponent
{
public:
float steelPrice = 1.5;
};
class MotorPoweredVehicle: public SteelComponent
{
public:
   
float enginePrice = steelPrice * 380;
};

class WheeledVehicle: public SteelComponent
{
public:
   
float wheelPrice = steelPrice * 500;
};

class Car: public MotorPoweredVehicle, public WheeledVehicle
{
public:
string model;
float carSteelCost;
};

int main()
{
Car opel;
opel.model = "Opel Corsa";
opel.carSteelCost = opel.wheelPrice + opel.enginePrice;

cout << "Total price for steel was: $" << opel.carSteelCost;
cout << " and the steel price was $" << opel.steelPrice << "/kg";
}