Ambiguity in Inheritance

In few cases of multiple inheritance, situation may occur that two base classes have the same members and as such an ambiguity occurs for accessing any one of the same named members.

Consider the below program:

class A    

{

  public:

    int a;

    fun()

    {

    }

};

class B       

{

  public:

    int a;

    fun()

   {

   }

};

class C : public A, public B

{

};

int main()

{

  C obj;

  obj.fun();  //error as fun is defined in two base classes

   ...

}

On compiling the above code, produces an error. It is because the sub class D inherits A and B which have same members which produces ambiguity on calling any one of the same named member function. It can be resolved by using scope resolution operator:


Example: 

//C++ program to remove ambiguity in inheritance using scope resolution operator

#include<iostream.h>

#include<conio.h>

using namespace std;

class A

{

  public:

    int a;

    fun()

   {

      cout<<"a= "<<a;

   }

};

class B

{

  public:

    int a;

    fun()

    {

    cout<<"a= "<<a;

  }  

};

class C : public A, public B

{

};

int main()

{

  C obj;

 obj.B::a= 5;

 obj.B::fun();        //fun of B called

 cout<<endl;

 obj.A::a= 10;

 obj.A::fun();         //fun of A called

  return 0;

}

OUTPUT:




Here, two separate values for a is created using the scope resolution operator. 


The Diamond problem


In some cases of inheritance, situations may occur that a derived class can inherit more than one copy of the base class. 

For example:

class A

{

  public:

    fun()

    {

       int a;

    }

};

class B: public A

{

};

class C : public A

{

};

class D: public B, public C

{

};

int main()

{

  D obj;

  obj.a;     //error due to multiple copy of the ultimate base class

  ...

}


In the above example, classes B and C contain single copy of A. But, class D inherit both B and C. Hence, D contains two copies of A, one from B and another from C which causes ambiguity. And, on compiling, it produces an error. Now, what if you actually require only single copy of the base class? To make it unambiguous and to get a single copy of the base class, make use of virtual base class.


Virtual Base class:

 A class is declared as virtual base class by using a keyword virtual. C++ takes necessary care of single copy of members of 

the base class to be inherited by the derived classes regardless any number of derived classes that use virtual base.


Syntax:

class sub_class : virtual access_mode super_class         //can also be written as, access_mode virtual super_class

{

};


 Example:

//C++ program to demonstrate virtual base class

#include<iostream>

#include<conio.h>

using namespace std;

class A

{

  public:

    int a;

    fun()

    {

      a= 11;

      cout<<"Value of a is: "<<a<<endl;

    }

};

class B: virtual public A

{

};

class C : virtual public A

{

};

class D: public B, public C

{

};

int main()

{

  D obj;       //unambiguous

  obj.fun();  

  cout<<"Removing ambiguity using virtual base class.";

  return 0;

}

OUTPUT:







Pure virtual function:

It is an empty function. It is declared using keyword virtual and assigning 0. It is also known as abstract function.


Syntax:

class class_name

{

  access_mod:

    virtual fun_name()= 0;

  ...

};


Abstract Class(or, ABC): A class which contains at least one pure virtual function is called an abstract class. 


Properties:

i.  It is a class which can't be instantiated or whose objects can't be created.

ii. If a sub class needs to be instantiated, it has to implement each abstract function of the base class.

iii. We can create constructors of an abstract class.

iv. Pointers and refrences can be used to abstract class type. We will discuss about pointers on later section.

Consider the below examples to understand the concept of abstract class.


 Example 1:

//C++ program to demonstrate abstract class

#include<iostream.h>

#include<conio.h>

using namespace std;

class A            //abstract class

{

  public:

    int a, b;

    virtual int sum()= 0;        //pure virtual function

    show()

   {

      a=7;   

      b=9;

    }

};

class B: public A          //sub class

{

  public:

    int sum()       //defining the abstract function

    {

      return (a+b);

    }

};

int main()

{

  B ob;

  ob.show();

  cout<<"a= "<<ob.a<<"\nb= "<<ob.b<<endl;

  cout<<"Sum of a and b= "<<ob.sum();

  return 0;

}

OUTPUT:





Example 2:

//C++ program to demonstrate abstract class with constructor

#include<iostream.h>

#include<conio.h>

using namespace std;

class base      //abstract class

{

  public:

    int a, b;

    virtual int sum() = 0;       //abstract function

    base()         //cunstructor

    {

       a= 15;

       b= 20;

     }

};

class sub: public base         //sub class

{

  public:

    sum()        //defining abstract class

    {

      return (a+b);

    }

};

int main()

{

  sub obj;

  cout<<"Sum of a and b: "<<obj.sum()<<endl;

  return 0;

}

OUTPUT:




Uses of Abstract Class


i. It provides an appropriate base class from which sub classes can be derived.

ii. It acts as an interface.

iii. It is extended by sub classes to provide full implementation. 


Note: If a sub class does not override the abstract function, then it also becomes an abstract class.


Constructors and Destructors in base and derived Classes


It is very important to know the order of execution of the class members when an objects for the sub classes are created and when it is destructed:

i. When an object for the derived class is created, constructor of the base class is called at first, followed by the constructor of derived class. 


ii. When an object of derived class is destroyed (at the time of its creation), destructor of the derived class is called first, followed by the  destructor of base class.


Hence, we can say that, constructors are called in order of their derivation, whereas, destructors are called in the reverse order.


Example:

//C++ program to demonstrate the order of constructors and destructors in inheritance

#include<iostream.h>

#include<conio.h>

using namespace std;

class A

{

  public:

    A()

    {

       cout<<"A's constructor called."<<endl;  

    }

    ~A()

    {

       cout<<"A's destructor called.";

    }

};

class B : public A

{

  public:

    B()

    {

       cout<<"B's constructor called."<<endl;

    }

    ~B()

    {

       cout<<"B's destructor called."<<endl;

    }

};

int main()

{

  B obj;

  return 0;

}

OUTPUT:




Parameterized base class constructor


In the sub classes constructors, parameters are simply passed using the standard parameterized constructor syntax. Now, in order to pass arguments in the base class constructor, we need to declare an expanded form of derived classe constructor which passes along arguments to the base class constructor. 


Example:

//C++ program to demonstrate parameterized base class constructor

#include<iostream.h>

#include<conio.h>

using namespace std;

class A

{

  public:

   int a;

   A(int x)        //parameterized constructor

   {

     a=x;

     cout<<"Value of a: "<<a<<endl;  

    }

};

class B : public A         

{

  public:

    B(int c): A(c)        //parameterized constructor

    {

      int y=c;

      cout<<"An example of parameterized base class constructor.";

    }

};

int main()

{

 B obj(11);

 return 0;

}

OUTPUT: