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 whetherA1::foo
orA2::foo
should be called -b.foo()
doesn’t compile. We need to disambiguate withb.A1::foo()
orb.A2::foo()
Is this syntax allowed in single inheritance?
If you had something like
class B: public A
, can you doB.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
*/