×
>
<

Aptitude

Polymorphism in C++

Polymorphism in C++

Polymorphism basically means having multiple existent forms in the program, A simple code may behave differently in different situations. For example, we have only one identity, to some we are friends, or father, student, employee etc.

In C++, polymorphism, generally happens because of classes objects and events are related with inheritance and hierarchy.

Types of Polymorphism

Polymorphism is of two types –

Compile time polymorphism (demonstrates static/early binding)

  • Function Overloading
  • Operator Overloading

Run time polymorphism (demonstrates dynamic/late binding)

  • Function Overriding (Achieved with help of virtual keyword)

Compile Time Polymorphism
Function Overloading

This happens when in a given program there are multiple functions with the same name but different arguments inside it or different parameters.

Example
  
#include
using namespace std;

class myClass {
    public:
    void myFunction(int a)
    {
        cout << "Accepted integer value " << a << endl;
    }
  
    void myFunction(double a) {
        cout << "Accepted double value " << a << endl;
    }
  
    void myFunction(int a, int b) 
    {
        cout << "Accepted multiple values, Value1:" << a << endl;
        cout << "Accepted multiple values, Value2:" << b << endl;
    }
};

int main() {
    myClass myclassObj;

    // will go to function with int as passed on variable as value passed is int type
    myclassObj.myFunction(5);

    // will go to function with double 
    myclassObj.myFunction(500.263);

    // will go to function with multiple parameters
    myclassObj.myFunction(5,3);

    return 0;
}
  
output
  
Accepted integer value 5
Accepted double value 500.263
Accepted multiple values, Value1: 5
Accepted multiple values, Value2: 3
  

Now, in the above, the functions go to their correct argument type in myClass this is called function overloading.

Note : Functions with the same name but different return types. Example void myFunction(int a), int myFunction(int a) will throw error.

Note : Pointer * vs Array int fun(int *ptr); || int fun(int ptr[]); // redeclaration of fun(int *ptr) can't be overloaded.

Operator Overloading

Operator overloading is possible in C++, you can change the behaviour of an operator like +, -, & etc to do different things.

For example, you can use + to concatenate two strings.

Consider two strings s1 and s2, we can concatenate two strings s1 and s2 by overloading + operator as String s, s = s1 + s2;

For Example – We know that ++x increments the value of x by 1. What if we want to overload this and increase the value by 100. The program below does that.

Example
  
#include 
using namespace std;

class Test
{
    private:
    int count;

    public:
    Test(): count(101)
    { 
        //writing fuction name followed by data member and passed on value works like constructor
        // Test(): count(101) same as writing count = 101; here
    }

    // we write operator before overloading such operators
    void operator ++() 
    { 
        count = count+100; 
    }
  
    void Display() 
    {
        court << "Count: " << count; 
    }
};

int main()
{
    Test t;
  
    // this calls "function void operator ++()" function
    ++t; 
  
    t.Display();
  
    return 0;
}
  
output
  
201
  

Operators that can be overloaded -

+ - * / % ^
& | ~ ! , =
< > <= >= ++ --
<< >> == != && ||
+= -= /= %= ^= &=
|= *= <<= >>= [] ()
-> ->* new new [] delete delete []

Operators that Can't be overloaded

:: .* . ?:

Runtime Polymorphism

There are two ways run time polymorphism may be achieved in C++

  1. Function Overriding
  2. Virtual Functions (Solves the problem of static resolution while working with pointers)

In a case when a function is declared in both the parent class(Base Class) and child class(Derived Class).

Example
  
#include
using namespace std;

// This is Parent class
class Parent
{
    public:
    void print()
    {
        cout << "Parent Class printing" << endl;
    }
};

// This is Child class
class Child : public Parent
{
    public:

    // as we see that it is already declared in the parent function
    void print()
    {
        cout << "Child Class printing" << endl;
    }
};

int main()
{
    //Creating object for parent class
    Parent parent_object;

    //Creating object for child class
    //No need to get conused here its same as Child object2;
    //We are just called a default constructor
    Child child_object = Child();

    // This will go to the parent member function
    parent_object.print();

    // This will however, go to child member function
    // overrides the parent function as the object is of the child class
    child_object.print();
  
    return 0;
}
  
output
  
Parent Class printing
Child Class printing
  

What exactly happens at the backend?

Even though, the child class has inherited all the functions of the parent class and has the same function definition within itself. The call is made to function of the child class as the object is of the child class.

What is this called This is behaviour shown by the child class object is called function overriding and this happens at run time. The child object has overridden the function definition of parent class and chose to exhibit its own properties.

What if? Now, what if the child class didn't have its own function declaration, in this case, it would have gone ahead with the inherited parent class definition of the print() function.

Runtime Polymorphism using Virtual Function

  1. What if we create a pointer to the parent class
  2. And assign it to the address of the base class object

  
Parent *parent_object;

Child child_object;

parent_object = &child_object;
  

Now, we will expect the function called by parent_object to call the child object function right? Because the final address is pointed toward child_object location. Let us see what happens –

Note : In below example, compile time polymorphism happens. We will force runtime polymorphism later in 2nd example below when we force it using virtual functions

Example
  
#include
using namespace std;

// This is Parent class
class Parent
{
    public:
    void print()
    {
        cout << "Parent Class printing" << endl;
    }
};

// This is Child class
class Child : public Parent
{
    public:

    // as we see that it is already declared in the parent function
    void print()
    {
        cout << "Child Class printing" << endl; 
    } 
};
int main()
{
    Parent *parent_object;
    Child child_object;
    parent_object = &child_object;

    // catch of the program is here
    // also as we are dealing with pointers instead of . we need to use -> 
    parent_object->print();

    // In the above program instead of using pointers we can write
    // Parent parent_object = Child(); 
    // parent_object.print();
    // this would also give same results

    return 0; 
}
  
output
  
Parent Class printing
  

What happenned above (Static Resolution)

Now, this happens because of how C++ was written by its writer. Now, while run time polymorphism may exhibit dynamic (or late) binding.

But, this instance is a classic example of early binding as the print() function is set during the compilation of the program. The definition of C++ is written, forces this static call and is also called as static resolution.

Thus, the above is an example of Compile time polymorphism. Also known as early binding.

How to force into Runtime Polymorphism (Virtual Functions)

The issue caused by static resolution is solved by using virtual function that turns the early binding into late binding i.e. compile time process to runtime process.

Forcing Runtime Polymorphism using Virtual function

If we add a virtual keyword before the function in the parent(base) class we can force runtime polymorphism (Late binding).

Example
  
#include
using namespace std;

// This is Parent class
class Parent
{
    public:
    // adding virtual keyword here
    virtual void print()
    {
        cout << "Parent Class printing" << endl;
    }
};

// This is Child class
class Child : public Parent
{
    public:

    // as we see that it is already declared in the parent function
    void print()
    {
        cout << "Child Class printing" << endl; 
    } 
}; 

int main() 
{ 
    Parent *parent_object; 
    Child child_object; 
    parent_object = &child_object; 

    // catch of the program is here 
    // also as we are dealing with pointers instead of . we need to use ->
    parent_object->print();

    return 0;
}
  
output
  
Child Class printing
  
What exactly happenned

Using the virtual keyword guarentees that the base(parent) class function is overridden and dervided(child) class function is implemented

This is called as late binding at runtime, thus runtime polymorphism is implemented. We solved the problem of static resolution which had earlier forced early binding(Compile time polymorphism)