Multiple Inheritance in C++

In C++ a class can inherit from more than one class. Other languages which support multiple inheritance are python, perl, common lisp etc.

In  Java, C# and Ruby,  it is not possible to have 2 or more base classes for a given class. But C++ allows it.


Syntax for multiple inheritance is


class cls-name:public base-cls1,public base-cls2,public base-cls3
{
/*code*/
}

The base class list is comma separated and must have access specifier for each base class. Each of these base classes must have been declared earlier.

Derived class objects contains sub-objects of each of the base classes.
 
class LAnimal
{
 public:
 void walk()
 {
 cout<<"walks";
 }
};
class WAnimal
{
 public:
 void swim()
 {
 cout<<"swims";
 }
};
class Amphibian:public LAnimal,public WAnimal
{
};
int main()
{
 Amphibian frog;
 frog.walk();
 frog.swim();
} 

In the above example, class Amphibian inherits from 2 classes - LAnimal and WAnimal. It has members of both these base classes. It can call both walk() and swim() functions.

Constructors

The derived class constructor and destructors  in multiple inheritace will call all of the base class constructors and destructors.  The order of constructor invocations is same as declaration order of base classes. 

Amphibian constructor will call LAnimal constructor first, then WAnimal constructor and finally Amphibian constructor. And order of destructor invocation is reverse of order of constructor invocation.

Dreaded diamond problem and Virtual Inheritance

When there is a multilevel and multiple inheritance together,  derived class may contain more than one instance of an ancestor class. Accessing a member from this base class throws an ambiguity error.

class A
{
 int m;
public:
 void setm(int a){m = a;};
 int getm(){return m;}
 void print(){cout<<"m"<<m<<endl;}
};
class B: public A
{
public:
 B(){setm(10);};
};
class C:public A
{
public:
 C() {setm(20);};
};
class D:public B,public C
{
 /*multiple inherited class*/
};
int main()
{
 D obj;
 cout<<obj.getm();/*error*/
 obj.print();/*error*/
}

When we compile this program obj.print()throws ambiguity error.

obj has members of A class duplicated. It has 2 ms, one is set 10 in B class constructor. And the other is set to 20 in C class constructor. So obj.getm() causes a conflict, whether to use m from B class path or m from C class path. 

Similarly when calling print(), compiler is unable to decide whether to call print through C class or print through B class.

This is called dreaded diamond problem because of the shape of inheritance diagram.

To avoid this error, virtual inheritance is used. 

Virtual Inheritance

In virtual inheritance, in spite of multiple paths to a base class, base class object is included only once.

 
class A
{
 int m;
public:
 int getm(){return m;}
 void setm(int a){m = a;}
 void print(){cout<<"A print";}
};
class B:virtual public A
{
/***code**/
};
class C:public virtual A
{
/***code**/
};
class D:public B,public C
{
/**this has only one sub object of A*/
};
int main()
{
 /*code*/
 D obj;
 obj.print();/*No error*/
}

Both B and C class use virtual inheritance. So when D inherits from both B and C, it is inheriting only one sub-object of A class. So there is only one data member called m in D class and only one print function. There will not be any ambiguity when obj.print() function is called.

 Also observe that obj  causes  A class constructor to be called only once and A destructor to be called only once. 


And do you know what? This topic and other topics are explained nicely in my C++ app. May be you want to download it from google play.

Comments

Popular Posts