C++ Polymorphism and Virtual Function

- January 23, 2018
In this article an introduction to C++ Polymorphism and Virtual functions is discussed. Virtual function is a special function which is used for implementing Polymorphism techniques. It means that polymorphism is achieved through the use of virtual function.
The polymorphism is the most important feature of object-oriented programming (OOP). With polymorphism, it is possible to design a system that can be easily modified. The program logic becomes very simple. We can easily test, debug and modify programs.

What is Polymorphism?

Polymorphism is the combination of two words "poly" and "morphism". Poly means many and "morphism" means form. Polymorphism is a technique in which different operations can have the same name but they do slightly different work. For example, consider a conventional application that can draw three different types of graphs like line-graph, pie-graph and bar-graph. In conventional application, logic of program to draw graph may be written as:

CASE OF GRAPH-TYPE IF Graph-Type = Line-Graph THAN draw-Line-graph (data) IF Graph-Type = Pie-Graph THAN draw-Pie-graph (data) IF Graph-Type = Bar-Graph THAN draw-Bar-graph (data) End Case
Although this programming technique is very simple and straight forward, but adding new graph type could be difficult. The existing code of program would have to be updated accordingly.
In polymorphism, solution to problems like these exists. Suppose we define a base class "graph" and then define subclasses for different types of graphs. Each subclass has a member of function called "draw". This concept is called "Function Overriding". When any object instantiated by a subclass receives a message regarding "draw" operation, it will invoke (call up) its own "draw" operation. When a new graph type is added in the system, a subclass with its own "draw" member function is developed. The remaining subclasses need not to be changed.
Polymorphism is the ability for the objects of different classes related by inheritance to respond differently to the same function call. This technique helps to perform a number of operations to have the same name.
Polymorphism is implemented or achieved through Virtual Function. The overridden member function is called for execution through a base class pointer. The program selects the correct overridden function in the appropriate derived class associated with the object. By using the polymorphism feature, a program control might walk through a container, such as an array of pointers to object of the base class "graph" may contain addresses pf objects of derived classes line-graph, pie-graph and bar-graph etc. Calling a "draw" function will draw a correct graph using polymorphism.

What is Pointer to Object?

A pointer to an object of a class can also be declared. The members of an object can be accessed through the pointer to an object. The arrow member selection operator (->) is used to access them. It is denoted by a hyphen (-) and a greater than sign (>). This operator is also know as member access operator.
The general syntax to access a member of an object through its pointer is as follows:
  ptr -> member;  
Where: ptr: It represents the name of pointer to an object. ->: It represents the member access operator. It is used to access the member of the object through the pointer. member: It represents the name of the member.

Example of Pointer to Object:

A program example is given below in which pointer object of a class is declared and member function is accessed through member access pointer.

#include<iostream.h>
#include<canio.h>
      class ppp
        { 
           public:
           void test (void)
           {
             cout<<"Pointer to object"<<endl;
           }
        } ;
main ()
{
   ppp x, *p;
   p= &x;
   clrscr ();
   x.test ();      //calling function using object 'x'
   p->test ();      //calling function using object;
} 
In this program, 'x' is an object of class "ppp", while 'p' is pointer to object of the same class. In the main() function, member function "test" is called through object 'x' using dot operator. Similarly, the same function is called through pointer to object 'p' using arrow member selection operator (->).
A program may have a base class and several derived classes. When a pointer is declared to point to am object of the base class, it can also point to the object of classes derived from the base class.
When a base class pointer is used to point to an object of a derived class, the pointer type remains unchanged, its type remains that of the base class. When this pointer is used to access a member of a class with the member access operator (->), the pointer type determines which the actual function will be called. It always accesses the member of the class with which its type matches. Thus, it will execute the member function of the base class. This is the default method for execution of a member function through a pointer.
Example-2:
This program example has a base class and two derived classes. The base class and its derived classes have their member function and the names of their member functions are same.

#include<iostream.h>
#include<canio.h>
      class B
       {
            public:
            void ppp (void)
            {
               cout<<"ppp() of the base class\n";
            }
       };
       class D1 : public B
       {
          public:
          void ppp (void)
          {
              cout<<"ppp() of 1st derived class\n";
           }
         };
          class D2 : public B
          {
             public:
             void ppp (void)
           {
              cout<<"ppp () of 2nd derived class\n";
            }
            };
main()
{
   B *p;
   D1    x;
   D2    y;
   clrscr ();
   p = &x;
   p->ppp ();
   getch ();
}

In this program, B is the base class and D1 and D2 are two derived classes. The derived classes have been derived from the base class B. In the main() function, the objects declarations are:
Pointer 'p' of the base class B declared. Object 'x' of the derived class D1 is declared. Object 'y' of the derived class D2 is declared. Other statements inside the main() function are executed as follows:
  • The statement 'p = &x;' assigns the address of object 'x' of the derived class D1. When the statement "p->ppp ();" is executed, the member function of the base class is executed. Since the type of the pointer matches the type member function if the base class, the base class member function is executed. 
  •  Similarly, when the second statement "p->ppp ();" is executed after assigning the address of object 'y' of the derived class D2, again the member function of the base class is executed.

What is Virtual Functions in C++?

Virtual means existing in appearance but not in reality. A virtual function is a special member function defined in the base class and overridden in one or more derived classes. It means that name of the function and its signature in base and derived classes remains the same. Polymorphism is achieved through the use of virtual functions.
A virtual function is declared by using keyword "virtual" before function declaration in the base class. The functions with the same names are declared in the derived classes. However, the use of keyword "virtual" is optional for the functions of the same name in the derived classes. Once a function is declared as virtual in base class, it remains virtual in the inheritance hierarchy.

Example of Virtual Function:

Following program example explains the concept of virtual functions:

#include<iostream.h>
#include<canio.h>
      class  base1
      {
         public:
         virtual void print ()
         {
           cout<<"printf() function of virtual base class"<<endl;
          }
        };
        class derived: public base1
         {
           public:
           void print ()
          {
            cout<<"print() function of derived class"<<endl;
          }
         };
         class derive2 : public base1
          {
             public:
             void print ()
              {
                cout<<"print() function of derive2 class"endl;
               }
             };
main ()
 {
   base1 b;
   base1 *pb;
   derive1 d1;
   derive2 d2;
   pb = &b;
   pb->print();
   pb = &d1;
   pb->print();
   pb-> = &d2;
   pb->print();
   getch();
  }

In this program, the function "print" is declared as virtual in the base class. In the derived classes, the same function is redefined with the same name and signature but the keyword "virtual" is not used. Inside the main() function, four variables are declared, these are:
"b" which is an object of class 'base1'. "pb" which is a pointer to 'base1' object. "d1" which is an object of the derived class 'derive1'. "d2" which is an object of the derived class 'derive2'. The statements of the program are as follows:
The statement "pb = &b;" is used to assign the address of object 'b' to the pointer object 'pb'. The statement "pb->print();" is used to execute the 'print' function of the base class. The "pb = &d1;" is used to assign the address of object 'd1' of the derived class "derive1". The "pb->print();" is used to execute the 'print' function associated with derived class object 'd1'. The "pb = &d2;" is used to assign the address of object 'd2' of the derived class "derive2". The "pb->print();" is used to execute the "print" function associated with derived class object 'd2'.
Example-2:
Consider another example of polymorphism. Suppose a base class "shape" is defined. The circle, pie, square, triangle and rectangle classes are all derived from class "shape". Each class contains a function "draw". To draw any shape we can simply call function "draw" of the base class and program determines at run time, which "draw" function of the derived class to use. Usually, an array of pointers to object of the base class is declared to store the memory addresses of all the objects of the derived classes. The required virtual function of the derived class is directly selected by specifying the index value of an array.
Following is the code of program to explain this concept:

#include<iostream.h>
#include<canio.h>
      class shape
       {
         public:
         virtual void draw()
          {
            cout<<"draw() function of virtual base class"<<endl;
          }
        };
         class circle: public shape
        {
            public:
            void draw()
         {
            cout<<"draw() function of circle class"<<endl;
          }
        };
           class pie: public shape 
        {
           public:
           void draw()
         {
            cout<<"draw() function of pie class"<<endl;
         }
       };
           class square: public shape
         {
            public:
            void draw()
         {
           cout<<"draw() function of square class"<<endl;
          }
         };
            class triangle: public shape
 {
            public:
            void draw()
         {
           cout<<"draw() function of triangle class"<<endl;
          }
         };
           class rectangle: public shape
 {
            public:
            void draw()
         {
           cout<<"draw() function of rectangle class"<<endl;
          }
         };
main()
 {
   shape b;
   shape *pb[5];
   circle d1;
   pie d2;
   square d3;
   triangle d4;
   rectangle d5;
   pb [0] = &d1;
   pb [1] = &d2;
   pb [2] = &d3;
   pb [3] = &d4;
   pb [4] = &d5;
   clrscr();
   for (int i = 0; i <= 4; i++)
           pb [i] -> draw();
   getch();
 }
In this program, an array of pointer 'pb' to object of the base class "shape" is declared. Similarly, the objects of the derived classes are declared. The addressee of these objects are assigned to elements of 'pb'. All the "draw" function of the derived classes are accessed through a single c++ loop statement.

What is Dynamic Binding & Early Binding?

The term binding refers to the connection between a function call and the actual code executed as a result of the call. The information required to call a member function can be decided at runtime or compile time.
The virtual function are accessed using a pointer to object of the base class. The program will choose the correct derived class overridden function at runtime, based on the object type (not the pointer or reference type). All the information required to call a function are decided at runtime. This is called dynamic binding.
The dynamic binding is also called late binding. With late binding, the compiler doesn't know in advance which function will be called because a function is called at runtime depending upon the value in the pointer during election of the program. The virtual function can be accessed by referring a specific object by name and using the dot operator (.). All information is required to call a function are finalized (or decided) at compile time. The virtual function will be called for execution, which is defined for the class of a particular object. This is called Early Binding. The early binding is also called static binding.

What is Pure Virtual Function?

A virtual function that is only declared but not defined in the base class is called pure virtual function. This function is initialized with value zero in its declaration in base class and has no definition relative to the base. Since it has no definition relative to the base, so any derived type must define its own version (definition of function).
The pure virtual function simply tells the compiler that the function is pure. The class that contains the pure virtual function exist only to act as a parent or base of the derived classes. This function is implemented in the derived classes.
If a class is derived from the base class having pure virtual function, then that virtual function remains pure in the derived class. Once a pure virtual function is used in the base class, then we must override it in all the derived classes.
The general syntax to declare a pure virtual function is as follows:
 
  virtual type func_name (parameters list) = 0;  
Where type: It represents the return data type of the pure virtual function. func_name: It represents the name of pure virtual function.

Example of Pure Virtual Function

The following code of the program uses pure virtual function.

#include<iostream.h>
#include<canio.h>

       class base1
         {
           public:
           virtual void print()  = 0;
         };
       class Derive1: public base1
       {
           public:
           void print()
           {
             cout<<"pure virtual function of Derive1 class"<<endl;
           }
         };
            class Derive2: public base1
           {
             public:
             void print ()
             {
                cout<<"pure virtual function of Derive2 class"<<endl;
              }
           };
main()
 {
   base1 *abs [2];
   Derive1 d1;
   Derive2 d2;
   abs [0] = &d1;
   abs [1] = &d2;
   clrscr ();
   for (int i = 0; i < =1; i++)
           abs [i] -> print();
   getch();
 }

What is Abstract Class & Concrete Class?
A class that has at least one pure function is called an Abstract Class. Such a class is used only as the base of derived classes. An abstract class can have both data members and member function. A derived class that is derived from abstract class must have definitions for every pure virtual function in its base. Otherwise it will be an abstract class too. If a class derived from an abstract class still has a pure virtual function, it is an abstract class also.
The abstract class can't be used to declare objects because it contains pure virtual function that has no definition. However, it can be used to declare pointers to an abstract base class.

What is the Purpose of Abstract Class?

The main purpose of the abstract class is to provide an appropriate base class from which classes may inherent interface. The classes from which objects can be created are called concrete classes. The concrete class has no pure virtual function. Usually, the derived classes don't have pure virtual function. The derived class that doesn't have any pure virtual function is called concrete derived class. The pure virtual function of an abstract base class is implemented in the concrete derived class.
In some cases, the abstract base class also provides an interface for the class hierarchy. Although a class hierarchy doesn't need to contain any abstract class but it is a good approach to develop object-oriented systems. The abstract base class is defined at the top of this hierarchy. the concrete derived classes are derived from the abstract base class. The pure virtual function is declared in the base class. Each derived class contains its own version of this pure virtual function.