Polymorphism in C++.

  • The term "Polymorphism" is the combination of "poly" + "morphs" which means many forms. 
  • It is a Greek word. In object-oriented programming, we use 3 main concepts: inheritance, encapsulation, and polymorphism.
  • Compile time polymorphism: The overloaded functions are invoked by matching the type and number of arguments. 
  • This information is available at the compile time and, therefore, compiler selects the appropriate function at the compile time. 
  • It is achieved by function overloading and operator overloading which is also known as static binding or early binding. 
  • Now, let's consider the case where function name and prototype is same.
  • Run time polymorphism: Run time polymorphism is achieved when the object's method is invoked at the run time instead of compile time. 
  • It is achieved by method overriding which is also known as dynamic binding or late binding.
  • Inheritance is a mechanism in which one object naturally acquires all of its parent object's properties and behaviors.
  • In C++, a pointer variable of a base class type can point to an object of its derived class. 
  • There are situations when this feature of C++ can be used to develop generic code for a variety of applications.

Pointer of base class

Consider the following program to understand pointer compatibility property

#include <iostream.h>
#include <conio.h>
class Shape
{
  protected:
    double width, height;
  public:
    void set_data (double a, double b)
    {
        width = a;
        height = b;
    }
};
class Rectangle: public Shape
{
  public:
    double area ()
    {
        return (width * height);
    }
};
int main ()
{
    Shape *sPtr;    //declare pointer variables of type Shape
    Rectangle Rect; //create the object rect of type Rectangle
    sPtr = &Rect;   //make sPtr point to the object rect.
    sPtr->set_data (5,3); //set length and width of object rect 
    cout << sPtr -> area() << endl;  //Compile Error !!
    return 0;
}
  • Notice that even though rectPtr is poining to rect (object of type Rectangle), when the program executes, the statement sets length and width of rectangle. 
  • If you tried to access area function of class Rectangle with sPtr it will give you compiler error.
sPtr -> area()
is a compiler error !
  • It means base class pointer can not access the additional member function of its derived class
  • If we want to do this we need to type cast the base class pointer.

Using Type Casts with Base Class Pointers

  • We can use a type cast to get the compiler to accept the statement:

static_cast <Rectangle *> (sPtr)->area()


so we should write the statement

cout << static_cast <Rectangle *> (sPtr) -> area() << endl;
  • The type cast informs the compiler that sPtr is actually pointing to a Rectangle object derived from the Shape base class. 
  • In general, a pointer to a base class that actually points to a derived class object must first be appropriately cast before the additional features of the derived class can be used.

#include <iostream.h>
#include <conio.h>
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      {
         cout << "Rectangle class area :" <<endl;
         return (width * height);
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      int area ()
      {
         cout << "Triangle class area :" <<endl;
         return (width * height / 2);
      }
};
// Main function for the program
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);
   // store the address of Rectangle
   shape = &rec;
   // call rectangle area.
   shape->area();
   // store the address of Triangle
   shape = &tri;
   // call triangle area.
   shape->area();
   return 0;
}
Expected Output:-
Parent class area

Parent class area

  • The reason for the incorrect output is that the call of the function area() is being set once by the compiler as the version defined in the base class. 
  • This is called static resolution of the function call, or static linkage - the function call is fixed before the program is executed. 
  • This is also sometimes called early binding because the area() function is set during the compilation of the program.
  • But now, let's make a slight modification in our program and precede the declaration of area() in the Shape class with the keyword virtual so that it looks like this:

class Shape
 {

   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      virtual int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
Expected Output:-

Rectangle class area

Triangle class area
Run time Polymorphism Example: By using two derived class

#include <iostream.h>
#include <conio.h>   
class Shape {                                        //  base class  
    public:    
virtual void draw(){                             // virtual function  
cout<<"drawing..."<<endl;      
    }        
};     
class Rectangle: public Shape                  //  inheriting Shape class.  
{      
 public:    
 void draw()      
   {      
       cout<<"drawing rectangle..."<<endl;      
    }      
};    
class Circle: public Shape                        //  inheriting Shape class.  
  
{      
 public:    
 void draw()      
   {      
      cout<<"drawing circle..."<<endl;      
   }      
};    
int main(void) {    
    Shape *s;                               //  base class pointer.  
    Shape sh;                               // base class object.  
       Rectangle rec;    
        Circle cir;    
      s=&sh;    
     s->draw();     
        s=&rec;    
     s->draw();      
    s=?    
    s->draw();     
}    
Expected Output:-

drawing...
drawing rectangle...
drawing circle...
Runtime Polymorphism with Data Members
  • Runtime Polymorphism can be achieved by data members in C++. 
  • Let's see an example where we are accessing the field by reference variable which refers to the instance of derived class.


#include <iostream.h>
#include <conio.h>    
class Animal {                                          //  base class declaration.  
    public:    
    string color = "Black";      
};     
class Dog: public Animal                       // inheriting Animal class.  
{      
 public:    
    string color = "Grey";      
};    
int main(void) {    
     Animal d= Dog();      
    cout<<d.color;     
}    
Expected Output:-

Black

Difference between Compile time polymorphism and run time polymorphism


Post a Comment

Previous Post Next Post