So far, all of the examples of inheritance we’ve presented have been single inheritance -- that is, each inherited class has one and only one parent. However, C++ provides the ability to do multiple inheritance. Multiple inheritance enables a derived class to inherit members from more than one parent.
Let’s say we wanted to write a program to keep track of a bunch of teachers. A teacher is a person. However, a teacher is also an employee (they are their own employer if working for themselves). Multiple inheritance can be used to create a Teacher class that inherits properties from both Person and Employee. To use multiple inheritance, simply specify each base class (just like in single inheritance), separated by a comma.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <string> class Person { private: std::string m_name; int m_age; public: Person(std::string name, int age) : m_name(name), m_age(age) { } std::string getName() { return m_name; } int getAge() { return m_age; } }; class Employee { private: std::string m_employer; double m_wage; public: Employee(std::string employer, double wage) : m_employer(employer), m_wage(wage) { } std::string getEmployer() { return m_employer; } double getWage() { return m_wage; } }; // Teacher publicly inherits Person and Employee class Teacher: public Person, public Employee { private: int m_teachesGrade; public: Teacher(std::string name, int age, std::string employer, double wage, int teachesGrade) : Person(name, age), Employee(employer, wage), m_teachesGrade(teachesGrade) { } }; |
Problems with multiple inheritance
While multiple inheritance seems like a simple extension of single inheritance, multiple inheritance introduces a lot of issues that can markedly increase the complexity of programs and make them a maintenance nightmare. Let’s take a look at some of these situations.
First, ambiguity can result when multiple base classes contain a function with the same name. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <iostream> class USBDevice { private: long m_id; public: USBDevice(long id) : m_id(id) { } long getID() { return m_id; } }; class NetworkDevice { private: long m_id; public: NetworkDevice(long id) : m_id(id) { } long getID() { return m_id; } }; class WirelessAdapter: public USBDevice, public NetworkDevice { public: WirelessAdapter(long usbId, long networkId) : USBDevice(usbId), NetworkDevice(networkId) { } }; int main() { WirelessAdapter c54G(5442, 181742); std::cout << c54G.getID(); // Which getID() do we call? return 0; } |
When c54G.getID()
is compiled, the compiler looks to see if WirelessAdapter contains a function named getID(). It doesn’t. The compiler then looks to see if any of the parent classes have a function named getID(). See the problem here? The problem is that c54G actually contains TWO getID() functions: one inherited from USBDevice, and one inherited from NetworkDevice. Consequently, this function call is ambiguous, and you will receive a compiler error if you try to compile it.
However, there is a way to work around this problem: you can explicitly specify which version you meant to call:
1 2 3 4 5 6 7 |
int main() { WirelessAdapter c54G(5442, 181742); std::cout << c54G.USBDevice::getID(); return 0; } |
While this workaround is pretty simple, you can see how things can get complex when your class inherits from four or six base classes, which inherit from other classes themselves. The potential for naming conflicts increases exponentially as you inherit more classes, and each of these naming conflicts needs to be resolved explicitly.
Second, and more serious is the diamond problem, which your author likes to call the “diamond of doom”. This occurs when a class multiply inherits from two classes which each inherit from a single base class. This leads to a diamond shaped inheritance pattern.
For example, consider the following set of classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class PoweredDevice { }; class Scanner: public PoweredDevice { }; class Printer: public PoweredDevice { }; class Copier: public Scanner, public Printer { }; |
Scanners and printers are both powered devices, so they derived from PoweredDevice. However, a copy machine incorporates the functionality of both Scanners and Printers.
There are many issues that arise in this context, including whether Copier should have one or two copies of PoweredDevice, and how to resolve certain types of ambiguous references. While most of these issues can be addressed through explicit scoping, the maintenance overhead added to your classes in order to deal with the added complexity can cause development time to skyrocket. We’ll talk more about ways to resolve the diamond problem in the next lesson.
Is multiple inheritance more trouble than it’s worth?
As it turns out, most of the problems that can be solved using multiple inheritance can be solved using single inheritance as well. Many object-oriented languages (eg. Smalltalk, PHP) do not even support multiple inheritance. Many relatively modern languages such as Java and C# restrict classes to single inheritance of normal classes, but allow multiple inheritance of interface classes (which we will talk about later). The driving idea behind disallowing multiple inheritance in these languages is that it simply makes the language too complex, and ultimately causes more problems than it fixes.
Many authors and experienced programmers believe multiple inheritance in C++ should be avoided at all costs due to the many potential problems it brings. Your author does not agree with this approach, because there are times and situations when multiple inheritance is the best way to proceed. However, multiple inheritance should be used extremely judiciously.
As an interesting aside, you have already been using classes written using multiple inheritance without knowing it: the iostream library objects std::cin and std::cout are both implemented using multiple inheritance!
Rule
Avoid multiple inheritance unless alternatives lead to more complexity.
![]() |
![]() |
![]() |
Maybe I missed it, but is everything inheritable inherited all inclusively all the time or can you pick and choose?
class A_Bazzillion_Public_Things
{
// I have a bazzillion public things
};
class Six_Things_Of_Yours : A_Bazzillion_Public_Things
{
// I only want 6 of your public things, or do I have to take them all?
};
Clearly I'm new to inheritance, but I have 2 classes which of each have many public things. However, I only want 1 from one and 2 from the other. I'm not sure how to look "under the hood" and discover stack/heap allocation (which might be a good thing because if I did, I'd do that literally for everything burning a lot of time :-/ ... damn, now I want to know. Do you know?)
Inheritance is all or nothing. You can change the access level of various members though, so you could inherit everything and then hide the stuff you don't want.
If you want to do something like what you're suggesting, I question whether inheritance is really the right model. You might be better off with either a composition class or a new class entirely.
Thank you Alex. I'm using (or might not now) an Arduino library that has a lot of public things. I guess if I ever write my own little library I should be more cautious of what is public.
>>There are many issues that arise in this context, including whether Copier should have one or two copies of PoweredDevice
Would you explain what you meant by the sentence above? What doe you mean by 'whether Copier should have one or two copies of PoweredDevice'?
Hi, I believe the last line (rule) should be enclosed with a gray or green box to make it stand out and easier to read. Other lessons follow this design.
"Rule: Avoid multiple inheritance unless alternatives lead to more complexity."
Hi, code tags on this page also appear to be broken (alongside 11.6b).
what is syntax of diamond problems?
Does this answer your question?
No. It doesn't illustrate the "diamond" problem. It's the same without the class A:
I'd rather write it this way:
Hi Alex,
Hope you don't mind readers pointing out typos :)
>> you have already been using classes written using multiple "inherited"
I don't mind at all. Thanks for pointing out the typo. It's been fixed!
Typo?
"Many relatively modern languages such as Java and C# restricts classes to single inheritance of normal classes..."
=>
"Many relatively modern languages such as Java and C# *restrict* classes to single inheritance of normal classes..."
Hi Alex,
First of all thank you for this tutorial it is perfect and help me a lot (still is).
I just notice one small typo I have encountered.
m_nTeachesGrade(teachesGrade)
the member variable is defined without n (m_teachesGrade)
Keep up the good work and thank you once again.
BR from Split, Croatia,
Frane
Fixed, thanks!
Hey Alex, might want to s/adaptor/adapter...
https://books.google.com/ngrams/graph?content=adapter%2Cadaptor&year_start=1800&year_end=2000&corpus=5&smoothing=3&direct_url=t1%3B%2Cadapter%3B%2Cc0%3B.t1%3B%2Cadaptor%3B%2Cc0
Otherwise, very useful post. I appreciate this site a lot.
Hah, was just a typo (propagated via copy/paste). I wasn't trying to bring the archaic spelling back. :) Thanks for pointing that out.
Does this course talk about inheritance like:
Topics such as that one are covered in the next chapter.
So in the first example of multiple inheritance a Teacher is-a Person but is also an Employee. However, an Employee is not a Person? How very totalitarian of you Alex!
You say totalitarian, I say visionary! I certainly wouldn't want non-Terran lifeforms to feel excluded from our corporate hierarchies.
Lol! Not sure I'd want to be taught by a non-Earthican teacher - they may have a whole different set of rules on classroom etiquette!
Hahaha!
I love this exchange! Would be great if the diamond example started off with Daren's comment and went into the problems!
May be I have made some silly mistakes here, but I can't figure it out:
Compiler throws 7 errors and all of them live inside overloaded operator (<<) function. What's bad?
Thanks..
You've declared para as a const, but the functions it accesses (p_name(), p_age(), etc...) are not const. It's really complaining about a const mismatch.
Best practice here would be to make all of the get accessor functions const. You should also make para a reference so it avoids making a copy when the function is called.
Worked, Thanks again :-)
Just a quick note about the order of the constructor to be called in case of multiple inheritance.
It will always be from left to right during derived class declaration.Irrespective of the order of the constructor called during initializer list.
For exercise try this