Wednesday, 19 November 2014

What is the diamond problem and what is the virtual base class in C++?

What is the diamond problem and what is the virtual base class in Cpp?

Let us see at below diagram, which helps us in explaining the diamond problem.



In the above picture we have 2 classes B and C that derive from the class – A.  We also have class D that derives from both B and C by using multiple inheritance.
The compiler will gets confused that from which base it need to take.


using namespace std;
/*This is my base class */
class MyBaseClass
{
       public:
          MyBaseClass();
          virtual ~MyBaseClass();
          void MyFun ();
};
MyBaseClass::MyBaseClass ()
{
   cout << "Constructor of MyBaseClass" << endl;
}
void MyBaseClass::MyFun ()
{
 cout << "I am in the Function" << endl;
}
MyBaseClass::~MyBaseClass ()
{
   cout << "Destructor of MyBaseClass" << endl;
}
/*This is my derived class which is derived from the base*/
class MyDerivedClass: public MyBaseClass
{
     //Doing a lot of jobs by extending the functionality
       public:
           MyDerivedClass() { cout << "Constructor of MyDerivedClass" << endl; }
           ~MyDerivedClass() { cout << "Destructor of MyDerivedClass" << endl; }
};
class MyDerived2Class: public MyBaseClass
{
     //Doing a lot of jobs by extending the functionality
       public:
           MyDerived2Class() { cout << "Constructor of MyDerived2Class" << endl; }
           ~MyDerived2Class() { cout << "Destructor of MyDerived2Class" << endl; }
};
class MyDerived3Class: public MyDerivedClass, public MyDerived2Class
{
     //Doing a lot of jobs by extending the functionality
       public:
           MyDerived3Class () { cout << "Constructor of MyDerived3Class" << endl; }
           ~MyDerived3Class () { cout << "Destructor of MyDerived3Class" << endl; }
      };
int _tmain (int argc, _TCHAR* argv[])
{
  MyDerived3Class ocClas;
  ocClas.MyFun ();
    getchar ();
    return 0;
}

In the code above, we’ve given a more concrete example of the diamond problem. The MyBaseClass class corresponds to the topmost class in the hierarchy (A in our graphic above), MyDerivedClass  and MyDerived2Class respectively correspond to B and C in the graphic, and the MyDerived3Class class corresponds to D.
So, let us look at the output of the above program
1>TestCPP.cpp(100): error C2385: ambiguous access of 'MyFun'
1>          could be the 'MyFun' in base 'MyBaseClass'
1>          or could be the 'MyFun' in base 'MyBaseClass'
1>TestCPP.cpp(100): error C3861: 'MyFun': identifier not found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

In our inheritance hierarchy, we can see that both the MyDerivedClass  and MyDerived2Class classes derive from the MyBaseClass base class.

And here is the problem: because MyDerived3Class derives from both the MyDerivedClass  and MyDerived2Class classes, which each have their own copy of the data members and methods of the MyBaseClass class.

At the end the the MyDerived3Class class object   ocClas will contain two object of the MyBaseClass base class.

The compiler gets confused which copy of the base object to be taken, so the compiler throws an error that reports as shown above

What is the solution to the Diamond Problem?

The below is the solution for the diamond problem.
If the inheritance from the MyBaseClass class to both the MyDerivedClass  and MyDerived2Class class is marked as virtual, then C++ will ensure that only one sub object of the MyBaseClass class will be created for every MyDerived3Class object.
Let us have a look into the example. Copy and compile it.
using namespace std;
/*This is my base class */
class MyBaseClass
{
       public:
          MyBaseClass();
          virtual ~MyBaseClass();
          void MyFun ();
};
MyBaseClass::MyBaseClass ()
{
   cout << "Constructor of MyBaseClass" << endl;
}
void MyBaseClass::MyFun ()
{
   cout << "I am in the Function" << endl;
}
MyBaseClass::~MyBaseClass ()
{
   cout << "Destructor of MyBaseClass" << endl;
}
/*This is my derived class which is derived from the base*/
class MyDerivedClass:  virtual public MyBaseClass
{
     //Doing a lot of jobs by extending the functionality
       public:
           MyDerivedClass() { cout << "Constructor of MyDerivedClass" << endl; }
           ~MyDerivedClass() { cout << "Destructor of MyDerivedClass" << endl; }
};
class MyDerived2Class: virtual public MyBaseClass
{
     //Doing a lot of jobs by extending the functionality
       public:
           MyDerived2Class() { cout << "Constructor of MyDerived2Class" << endl; }
           ~MyDerived2Class() { cout << "Destructor of MyDerived2Class" << endl; }
};
class MyDerived3Class: public MyDerivedClass, public MyDerived2Class
{
     //Doing a lot of jobs by extending the functionality
       public:
           MyDerived3Class () { cout << "Constructor of MyDerived3Class" << endl; }
           ~MyDerived3Class () { cout << "Destructor of MyDerived3Class" << endl; }
};
int _tmain (int argc, _TCHAR* argv[])
{
  MyDerived3Class ocClas;
  ocClas.MyFun ();
    getchar ();
    return 0;
}

In the above program we have derived the base class using "virtual" keyword to the MyDerivedClass and MyDerived2Class class declarations. Now the MyDerived3Class class object will have only one MyBaseClass sub object, and the code below will compile just fine, the output of the above program is
Constructor of MyBaseClass
Constructor of MyDerivedClass
Constructor of MyDerived2Class
Constructor of MyDerived3Class
I am in the Function





No comments: