Showing posts with label Multiple Inheritance. Show all posts
Showing posts with label Multiple Inheritance. Show all posts

Sunday, August 30, 2015

Problem with Multiple Inheritance in C++ (Diamond Problem)

Multiple Inheritance


 In multiple inheritance a derived class inherits from more than one class.The following figure gives an idea.

                                                   
                                                                   Figure 1

In Figure 1 class D is the derived class and B,C are base classes for it.


Problems with Multiple Inheritance


Consider the following program:
#include<iostream>
using namespace std;

class B{
private:
 int b_var;
public:
   B(){
    b_var=10;
   }
   void display(int b){
    cout<<"Called from B and value is"<<b<<"\n";
   }
};
class C{
private:
 int c_var;
public:
   C(){
    c_var=30;
   }
   void display(int c){
    cout<<"Called from C and value is"<<c<<"\n";
   }
};
class D:public B,public C{

public:
 int d_var;
   D(){
    d_var=40;
   }
 };

int main(){
 D dobject;
 dobject.display(dobject.d_var);
}
 We will get an error: request for member 'display' is ambiguous.
Why this happens? Think!!!

Let's look how the compiler evaluates the above program: 
After creating an object of type D when we call the function display using that object the compiler searches for display function in class D. As the compiler cannot find it then looks to see if any of the base classes have a function named display().
The problem is that 'dobject' actually contains two display() functions: one inherited from class B, and one inherited from class C. Therefore compiler cannot choose between the two and the function call is ambiguous, and will receive a compiler error.

How to solve this problem?

One way is to explicitly mention from which class the method has to be derived. This is known as explicit scoping.
dobject.B::display(dobject.d_var);

And the output is:
Called from B and value is 40

Diamond Problem

Let's complicate things a bit more. Now have a look at the following figure:

                                                                Figure 2

   If the function display is derived from A the program looks like this:
class A{
private:
 int a_var;
public:
   A(){
    a_var=100;
   }
   void display(int a){
    cout<<"Called from A and value is "<<a<<"\n";
   }
};

class B:public A{
private:
 int b_var;
public:
   B(){
    b_var=10;
   }

};
class C:public A{
private:
 int c_var;
public:
   C(){
    c_var=30;
   }

};
class D:public B,public C{

public:
 int d_var;
   D(){
    d_var=40;
   }
 };

int main(){
 D dobject;
 dobject.display(dobject.d_var);

 return 0;
}

The same problem as in the case of multiple inheritance exists and also adds more problems to it.
The compiler doesn't know whether it should have one or two copies of A and how to resolve such ambiguous references. While these problems can be solved using explicit scoping but the maintenance overhead increases.

If we create object of type D then by default compiler ends up creating two copies of class A. As shown in the figure 3.


                                                                        Figure 3

Most of the times we want the compiler to create only one copy of class A.

Is it possible?
Yes, it is possible with the help of virtual base classes.

So let's make some changes to the code and make it work.
class A{
private:
 int a_var;
public:
   A(){
    a_var=100;
   }
   void display(int a){
    cout<<"Called from A and value is "<<a<<"\n";
   }
};

class B:virtual public A{
private:
 int b_var;
public:
   B(){
    b_var=10;
   }

};
class C:virtual public A{
private:
 int c_var;
public:
   C(){
    c_var=30;
   }

};
class D:public B,public C{

public:
 int d_var;
   D(){
    d_var=40;
   }
 };

int main(){
 D dobject;
 dobject.display(dobject.d_var);

 return 0;
}
 And the Output looks like: 
Called from A and value is 40

Here Class A is constructed only once. Before finishing this topic there are few points to be remembered.
First virtual base classes are created before non-virtual base classes, which ensures all bases get created before their derived classes. 

Second, note that the constructors of Classes B and C still have calls to the A's constructor. If we are creating an instance of D, these constructor calls are simply ignored because D is responsible for creating the A, not B or C. However, if we were to create an instance of B or C, the virtual keyword is ignored, those constructor calls would be used, and normal inheritance rules apply.

Third, if a class inherits one or more classes that have virtual parents, the most derived class is responsible for constructing the virtual base class.

Happy Learning....