Inheritance

Multiple Inheritance

Multiple inheritance is a feature of some OOP languages in which a class can inherit features from multiple parent classes.

A C++ class can inherit members from more than one class, the syntax is

class derived-class: access baseA, access baseB....

Multiple inheritance has been a controversial issue for many years, with opponents pointing to its increased complexity and ambiguity in situations such as the Diamond Problem.

Problems

Multiple inheritance can have some tricky semantics. Consider the following example:

class A1 {
	public:
		void foo() {cout << "A1::foo" << endl;};
};
 
class A2 {
	public:
		void foo() {cout << "A2::foo" << endl;};
};
 
class B: public A1, public A2 {};
B b{};
b.foo();  // ERROR: member 'foo' found in multiple base classes of different types
  • b.foo() is ambiguous - it’s not clear whether A1::foo or A2::foo should be called - b.foo() doesn’t compile. We need to disambiguate with b.A1::foo() or b.A2::foo()

Is this syntax allowed in single inheritance?

If you had something like class B: public A, can you do B.A::foo()?

  • Answer: Although not needed, yes you can do this! It’s using the Scope Resolution Operator ::

So how do we address ambiguity?

How to address ambiguity?

This can be addressed in various ways, including using Virtual Inheritance.

Alternate methods of object composition not based on inheritance such as mixins and traits have also been proposed to address the ambiguity.

But the most concerning problem is the Diamond Problem.

Other

What is the order of construction in multiple inheritance?

I didn’t consider this before, but what is the order of construction when we have multiple constructors? https://www.makeuseof.com/what-is-diamond-problem-in-cpp/

  • Answer: it’s just in the order that the superclasses are listed
#include<iostream>
using namespace std;  
class A //base class A with constructor and destructor  
{  
public:  
  A() { cout << "class A::Constructor" << endl; }  
  ~A() { cout << "class A::Destructor" << endl; }  
};  
class B //base class B with constructor and destructor  
{  
public:  
  B() { cout << "class B::Constructor" << endl; }  
  ~B() { cout << "class B::Destructor" << endl; }  
};  
class C: public A, public B //derived class C inherits class A and then class B (note the order)  
{  
public:  
  C() { cout << "class C::Constructor" << endl; }  
  ~C() { cout << "class C::Destructor" << endl; }  
};  
int main(){  
    C c;  
    return 0;  
}
 
/* OUTPUT
class A::Constructor
class B::Constructor
class C::Constructor
class C::Destructor
class B::Destructor
class A::Destructor
*/