Navigation



11.7 — Multiple inheritance

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.

#include <string>
class Person
{
private:
    std::string m_strName;
    int m_nAge;
    bool m_bIsMale;

public:
    Person(std::string strName, int nAge, bool bIsMale)
        : m_strName(strName), m_nAge(nAge), m_bIsMale(bIsMale)
    {
    }

    std::string GetName() { return m_strName; }
    int GetAge() { return m_nAge; }
    bool IsMale() { return m_bIsMale; }
};

class Employee
{
private:
    std::string m_strEmployer;
    double m_dWage;

public:
    Employee(std::string strEmployer, double dWage)
        : m_strEmployer(strEmployer), m_dWage(dWage)
    {
    }

    std::string GetEmployer() { return m_strEmployer; }
    double GetWage() { return m_dWage; }
};

// Teacher publicly inherits Person and Employee
class Teacher: public Person, public Employee
{
private:
     int m_nTeachesGrade;

public:
    Teacher(std::string strName, int nAge, bool bIsMale, std::string strEmployer, double dWage, int nTeachesGrade)
        : Person(strName, nAge, bIsMale), Employee(strEmployer, dWage), m_nTeachesGrade(nTeachesGrade)
    {
    }
};

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:

class USBDevice
{
private:
    long m_lID;

public:
    USBDevice(long lID)
        : m_lID(lID)
    {
    }

    long GetID() { return m_lID; }
};

class NetworkDevice
{
private:
    long m_lID;

public:
    NetworkDevice(long lID)
        : m_lID(lID)
    {
    }

    long GetID() { return m_lID; }
};

class WirelessAdaptor: public USBDevice, public NetworkDevice
{
public:
    WirelessAdaptor(long lUSBID, long lNetworkID)
        : USBDevice(lUSBID), NetworkDevice(lNetworkID)
    {
    }
};

int main()
{
    WirelessAdaptor c54G(5442, 181742);
    cout << c54G.GetID(); // Which GetID() do we call?

    return 0;
}

When c54G.GetID() is evaluated, the compiler looks to see if WirelessAdaptor contains a function named GetID(). It doesn’t. The compiler then looks to see if any of the base 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 WirelessDevice. 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:

int main()
{
    WirelessAdaptor c54G(5442, 181742);
    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:

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.

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# restricts 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 inherited without knowing it: the iostream library objects cin and cout are both implemented using multiple inheritance.

11.8 — Virtual base classes
Index
11.6 — Adding, changing, and hiding members in a derived class

9 comments to 11.7 — Multiple inheritance

  • [...] 2007 Prev/Next Posts « 11.5 — Inheritance and access specifiers | Home | 11.7 — Multiple inheritance » Thursday, January 17th, 2008 at 4:06 [...]

  • som shekhar

    The compiler then looks to see if any of the derived classes have a function named GetID().
    In the description of the class USBDevice and network adapter example::

    THE ABOVE LINE YOU HAVE MENTIONED SHOULD BE corrected…
    “the compiler then looks to see if any of the BASE/PARENT classses have a function named GetID()

  • mslade

    Hey, not sure how it happened, but your article has spam injected into it.

    Second paragraph: “Multiple inheritance can be used to create a Teacher class that inherits”. Fix it so the jerks don’t get any more free traffic off of your hard work. :)

  • luckyeights

    Could be more precise here:

    > When c54G.GetID() is evaluated, the compiler looks to see if WirelessAdaptor contains a function named GetID().

    1. More precise language would be helpful. This happens at evaluation time, so the compiler isn’t what’s doing this check.
    2. Because GetID() wasn’t declared as virtual, the base class’ GetID() function will be used anyway – it doesn’t matter if WirelessAdaptor contains a function GetId().

    Please correct me if I’m wrong, but this is my understanding.

    • luckyeights

      Whoops, I ran some tests and I think both the things I just said are wrong. Sorry about that.

      I’m not able to delete my comment, but if the author would like to, I think it would be a good idea.

  • pranavjain02.89

    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
    class Base
    {
    private:
    const int base;

    public:
    Base(int i):base(i){
    cout<<"In base\n";
    }
    int getBaseValue()
    {
    return base;
    }
    };

    class Base2
    {
    private:
    const int base2;

    public:
    Base2(int i):base2(i){
    cout<<"In base2\n";
    }
    int getBase2Value()
    {
    return base2;
    }
    };

    class Derived:public Base,public Base2
    {
    private:
    const int derived;
    public:
    Derived(int x, int y):Base2(x*2),Base(x),derived(y*2){
    cout<<"In dervied\n";
    }
    int getDerivedValue()
    {
    return derived;
    }
    };

    int main()
    {
    cout << "Hello World" << endl;
    Derived d(10,20);
    cout<<d.getBaseValue()<<"\n";
    cout<<d.getDerivedValue()<<"\n";
    return 0;
    }

  • some how confusing ….dis MULTIPLE INHERITANCE…….

    WHICH ONE IS COMING WHICH ONE…….

  • FINALLY UNDASTAND IT VERY WELL….

    FOR YOU TO UNDA DIS MULTIPLE INHERITANCE….. READ IT LINE BY LINE. DONT SKIP ANY…

    MR.ALEX EXPLAINED IT OKAY…..

    //…………

You must be logged in to post a comment.