By Stephen R. Davis

If one C++ class can inherit from another, then the question immediately arises, “Can a class inherit from two (or more) classes?” The answer in is an unqualified “Yes.”

It may be valuable to see a real-world example of multiple inheritance to understand why this is a capability worth having. Most universities offer jobs to graduate students as teaching assistants. These individuals are still students and have all the properties of a student — but, in addition, they are also afforded the features of an instructor. Thus, logically, their inheritance tree looks like this:

TeachingAssistant inherits from both Student “/>

A TeachingAssistant inherits from both Student and Instructor.

Expressed in C++, this would appear as follows:

class Student
{
  public:
    double gpa();
    bool  enroll(Course&);
    bool  pay(double dollars);
};
class Instructor
{
  public:
    double grade(Artifact&);
    bool  teach(Course&);
    bool  getPaid(double dollars);
};
class TeachingAssistant:public Student, public Instructor
{
  public:
    Instructor advisor(Instructor&);
    Instructor advisor();
};

The only difference between this example and examples of simple inheritance is the appearance of two class names after the declaration of TeachingAssistant.

Given the class definitions just shown, all of the following can be said:

TeachingAssistant ta;
// get a grade like a student
double d = ta.gpa();
// grade a paper like an instructor
ta.grade(document);
// I can pass a ta to a function that expects a Student
void party(Student&);
party(ta);
// or a function that expects an Instructor
void soiree(Instructor&);
soiree(ta);

So far, so good. What’s not to like about multiple inheritance?

Multiple ambiguities

Reviewing Student and Instructor classes, both of these classes share a property: a university-assigned identification number. But if you try to add this property as follows, you get nothing but complaints from C++:

class Student
{
  public:
    int    id();
    double gpa();
    bool  enroll(Course&);
    bool  pay(double dollars);
};
class Instructor
{
  public:
    int id();
    double grade(Artifact&);
    bool  teach(Course&);
    bool  getPaid(double dollars);
};
class TeachingAssistant:public Student, public Instructor
{
  public:
    Instructor advisor(Instructor&);
    Instructor advisor();

};

This trouble is shown graphically, here:

id() property to both Student and

Adding the id() property to both Student and Instructor causes confusion.

The problem is that now, when you say something like

TeachingAssistant ta;
cout << "TA's id is " << ta.id(); // which id?

which id() is intended — the one that TeachingAssistant inherits from Student or the one that it inherits from Instructor? The ambiguity can be resolved by specifying the path to id (known as the qualified name) like this:

cout << "TA's student id is " << ta.Student::id();

Now there’s no ambiguity. By specifying the base class, C++ is told which id() to pick.

Resolving the ambiguity: First attempt

But what if the two instances of id() are not different? Suppose that, like many universities, a particular university assigns a unique identification number to both students and instructors. In that case, what’s really wanted is the situation shown in the following image: Now a TeachingAssistant has but a single id() property.

id() property is inherited from a base class common to both

The id() property is inherited from a base class common to both Student and Instructor.

To try to express this state of affairs in C++, suppose the following is written:

class Academic
{
  public:
    int id();
};
class Student : public Academic
{
  public:
    double gpa();
    bool  enroll(Course&);
    bool  pay(double dollars);
};
class Instructor : public Academic
{
  public:
    double grade(Artifact&);
    bool  teach(Course&);
    bool  getPaid(double dollars);
};
class TeachingAssistant:public Student, public Instructor
{
  public:
    Instructor advisor(Instructor&);
    Instructor advisor();
};

Unfortunately (and quite surprisingly), this approach doesn’t solve the problem at all. A reference to ta.id() is still ambiguous. It turns out that this code doesn’t create the preceding image; instead, it creates the situation shown here:

A single base class can be inherited in the subclass multiple times.

A single base class can be inherited in the subclass multiple times.

It seems that TeachingAssistant now inherits Academic twice — once through its Student-ness, and again through its Instructor-ness. It now has a Student::Academic::id() and an Instructor::Academic::id().

Resolving the ambiguity

In order to achieve what appears in the third figure of this article in C++, you must fall back on something C++ calls virtual inheritance. This feature appears in action as follows:

class TeachingAssistant: virtual public Student, 
                         virtual public Instructor
{
  public:
    Instructor advisor(Instructor&);
    Instructor advisor();
};

The use of the virtual keyword tells C++ to combine any common base classes that Student and Instructor might share. The following no longer generates a compiler error:

cout << "TA's student id is " << ta.id(); // no error now

With virtual inheritance, TeachingAssistant inherits one and only one copy of Academic and the reference to ta.id() is no longer ambiguous.