Understanding the Concepts of Polymorphism in C++

What is Polymorphism? 

Polymorphism is one of the most important concepts of Object-Oriented Programming (OOPs). For a language considered to be an OOP language, it must support polymorphism. You can describe the word polymorphism as an object having many forms. Polymorphism is the notion that can hold up the ability of an object of a class to show different responses. In other words, you can say that polymorphism is the ability of an object to be represented in over one form.

To understand polymorphism, you can consider a real-life example. You can relate it to the relationship of a person with different people. A man can be a father to someone, a husband, a boss, an employee, a son, a brother, or can have many other relationships with various people. Here, this man represents the object, and his relationships display the ability of this object to be represented in many forms with totally different characteristics.

Polymorphism in C++ is broadly classified into two categories based on their characteristic features that you will explore further in this article. These categories are:

  • Compile-time Polymorphism
  • Run-time Polymorphism.

Add Another Star to Your Performance Evaluation

Learn from industry experts for FREEStart Learning
Add Another Star to Your Performance Evaluation

Why Do You Need to Use Polymorphism?

Polymorphism has several benefits associated with it. One of them is that it helps you write the code consistently. For example, suppose you want to find the area of a circle and a rectangle. For that, your first approach will be to create a base class that will deal with the type of polygon. This base class contains two derived classes, one for the circle and another one for the rectangle. Now, instead of declaring two separate functions with separate names in both the derived classes to calculate the area of each polygon, you can just declare one function in the base class and override it in the child classes to calculate the area. In this way, you increase the code consistency using polymorphism.

Types of Polymorphism

Based on the functionality, you can categorize polymorphism into two types:

  • Compile-Time Polymorphism

When the relationship between the definition of different functions and their function calls, is determined during the compile-time, it is known as compile-time polymorphism. This type of polymorphism is also known as static or early binding polymorphism. All the methods of compile-time polymorphism get called or invoked during the compile time.

You can implement compile-time polymorphism using function overloading and operator overloading. Method/function overloading is an implementation of compile-time polymorphism where the same name can be assigned to more than one method or function, having different arguments or signatures and different return types. Compile-time polymorphism has a much faster execution rate since all the methods that need to be executed are called during compile time. However, it is less preferred for handling complex problems since all the methods and details come to light only during the compile time. Hence, debugging becomes tougher.

The implementation of compile-time polymorphism is achieved in two ways:

  • Function overloading
  • Operator overloading

Before discussing them, it is essential to understand their other counterpart which is runtime polymorphism.

  • Runtime Polymorphism

In runtime polymorphism, the compiler resolves the object at run time and then it decides which function call should be associated with that object. It is also known as dynamic or late binding polymorphism. This type of polymorphism is executed through virtual functions and function overriding. All the methods of runtime polymorphism get invoked during the run time.

Method overriding is an application of run time polymorphism where two or more functions with the same name, arguments, and return type accompany different classes of the same structure. This method has a comparatively slower execution rate than compile-time polymorphism since all the methods that need to be executed are called during run time. Runtime polymorphism is known to be better for dealing with complex problems since all the methods and details turn up during the runtime itself.

The implementation of run time polymorphism can be achieved in two ways:

  • Function overriding
  • Virtual functions

Ways to Implement Compile-Time Polymorphism in C++

In C++, you can implement compile-time polymorphism in two ways. In this section, you will explore both of them in detail.

  • Function Overloading

Function overloading is an important pillar of polymorphism in C++. When the same function name is overloaded with multiple tasks, that function gets overloaded. In other words, function overloading takes place when you create two functions of the same name and these functions serve different purposes. Both functions should have the same return types and strictly different arguments from each other. It is achieved during the compile time. Function overloading can take place both in the base class as well as in the derived class.

All the functions that have been overloaded share the same scope. Since it is achievable in both the base class and the derived class, you do not specifically need inheritance. 

Syntax

// same name functions having different arguments

int func (int var) {}

int func (float var) {}

The following program illustrates compile-time polymorphism using function overloading:

#include <bits/stdc++.h>

using namespace std;

class functionOverloadingExample

{

    public:

    // function with 1 int parameter

    void myFunc(int a)

    {

        cout << "a = " << a << "\n\n";

    }

    // myFunction with same name but 1 double parameter

    void myFunc(double a)

    {

        cout << "a =  " << a << "\n\n";

    }

    // myFunction with same name and 2 int parameters

    void myFunc(int a, int b)

    {

        cout << "a = " << a << ", b = " << b << "\n\n";

    }

};

int main() {

    functionOverloadingExample obj;

    // Which myFunction is called will depend on the parameters passed

    // The first 'myFunc' is called

    obj.myFunc(10);

    // The second 'myFunc' is called

    obj.myFunc(10.20);

    // The third 'myFunc' is called

    obj.myFunc(100, 200);

    return 0;

}

PolymorphisminC_Plus_Plus_1

In the program above, there are three functions with the same name myFunc, but with different arguments. When a function call is made, the compiler decides the function which is to be called by matching the parameters passed. So, when you pass an integer value 10, it calls the function mFunc(int a). 

  • Operator Overloading

Operator overloading is sometimes referred to as ad-hoc polymorphism too. In operator overloading, different operators display different implementations based on their parameters or signatures. The C++ programming language allows you to create operators that can serve specific purposes with user-defined functions. This ability of C++ to create operators with a specific meaning for data types is termed operator overloading.  

A simple and common example of operator overloading is that when you use the “+” operator in between two or more strings. It is used to join or concatenate them. Some other use-cases of operator overloading are working with Fractional Numbers, Complex Numbers, Big integers, etc.

Syntax

class class_name {

    public

       return_type operator symbol (arguments) {

           // define the function

       } 

};

The following program illustrates compile-time polymorphism using operator overloading:

#include <iostream>    

using namespace std;    

// define a class

class operatorOverlaodingExample    

{    

   private:    

      int myVar;    

   public:    

       operatorOverlaodingExample(): myVar(8){}    

       void operator ++()         {     

          myVar = myVar + 20;     

       }    

       void display() {     

          cout << "The updated value is: " << myVar;     

          cout << "\n\n";

       }    

};  

int main()    

{    

    operatorOverlaodingExample obj; 

    // call the function "viod operator +++()"   

    ++obj;  

    obj.display();    

    return 0;    

}    

PolymorphisminC_Plus_Plus_2

The main difference between normal functions and operator functions is that the name of the operator functions is followed by the keyword “operator” along with the operator symbol that you want to overload. These operator functions get invoked when their corresponding operators are used in the program.

You can overload almost all operators supported by C++, but there are a few exceptions. These exception operators are:

  • .    (dot operator)
  • ::   (scope operator)
  • ?:  (ternary operator)
  • size of 

Some Key Points About Operator Overloading:

  • To overload an operator, it is necessary for at least one operand to be an object of a user-defined class.
  • In operator overloading, a default assignment operator gets created with every class automatically by the compiler. 
  • C++ allows you to create conversion operators that can convert one type of an operator into another type.

#include <iostream>

using namespace std;

// define a class to convert integers into float

class convertFloat

{

    int dividend, divisor;

public:

    // constructor

    convertFloat(int D, int d) 

    { 

        dividend = D; 

        divisor = d; 

    }

    // this is a conversion operator

    // it will convert an integer into float

    // and return it

    operator float() const {

        return float(dividend) / float(divisor);

    }

};

int main() {

    // call the operator

    convertFloat f(5, 9);

    float result = f;

    // print result

    cout << result;

    cout << "\n\n";

    return 0;

}

PolymorphisminC_Plus_Plus_3 

  • The constructors that have a single argument act as a conversion operator as well.

#include<iostream>

using namespace std;

// define a class

class coordinates

{

private:

    int x1, y1;

public:

    // constructor of the class

    coordinates(int x_coord = 0, int y_coord = 0) {

        x1 = x_coord ; 

        y1 = y_coord;

    }

    void displayCoordinates() {

        cout << "\n";

        cout << " The x-coordinate = " << x1 << ", The y-coordinate = " << y1;

        cout << "\n\n";

    }

};

int main() {

    coordinates point(100, 100);

    point.displayCoordinates();

    // x will be 30 and y will be 0

    point = 30;

    point.displayCoordinates();

    return 0;

}

PolymorphisminC_Plus_Plus_4 

Ways to Implement Run-time Polymorphism in C++

In C++, you can implement run-time polymorphism in two ways. In this section, you will see both of them in detail.

  • Function Overriding 

Function overriding takes place when your derived class and base class both contain a function having the same name. Along with the same name, both the functions should have the same number of arguments as well as the same return type. The derived class inherits the member functions and data members from its base class. So to override a certain functionality, you must perform function overriding. It is achieved during the run time. 

Functions that are overridden acquire different scopes. For function overriding, inheritance is a must. It can only happen in a derived class. If a class is not inherited from another class, you can not achieve function overriding. To sum up, a function is overridden when you want to achieve a task supplementary to the base class function.

The following program illustrates run-time polymorphism using function overriding:

#include <iostream>

using namespace std;

// define a base class

class bird

{

   public:

   // display function of the base class

   void display()

   {

      cout << "I am the display function of the base class";

      cout << "\n\n";

   }

};

class parrot:public bird

{

   public:

   // display function of the serived class

   // this function will display() 

   // of base class override at run time

   void display() 

   {

      cout << "I am the display function of the derived class";

      cout << "\n\n";

   }

};

int main()

{

   // create objects of base and child classes 

   bird b;

   parrot p;

   // call the diplay() function

   b.display();

   p.display();

}

PolymorphisminC_Plus_Plus_5

  • Virtual Functions

Virtual functions are the member functions of the base class which are overridden in a derived class. When you make a call to such a function by using a pointer or reference to the base class, the virtual function is called and the derived class’s version of the function gets invoked.

Some Key Points About Virtual Functions

  • Virtual functions are only dynamic
  • They are declared within a base class by using the keyword “virtual”
  • These functions are called during run time
  • Virtual functions are always declared with a base class and overridden in a child class
  • Virtual functions can exist in the absence of inheritance. In that case, the base class version of the function will be called

The following program illustrates run-time polymorphism using a virtual function:

#include <iostream>

using namespace std;

// define a base class bird

class bird {

public:

    // virtual function

    virtual void display()

    {

        cout << "This is display in bird class." << "\n\n";

    }

    void print()

    {

        cout << "This is show in bird class." << "\n\n";

    }

};

// define a child class parrot

class parrot : public bird {

public:

    void display()

    {

        cout << "This is display in parrot class." << "\n\n";

    }

    void print()

    {

        cout << "This is show in parrot class." << "\n\n";

    }

};

int main()

{

    // create a reference of class bird

    bird* brd;

    parrot p;

    brd = &p;

    // this will call the virtual function

    brd->display();

    // this will call the non-virtual function

    brd->print();

}

PolymorphisminC_Plus_Plus_6

Full Stack Web Developer Course

To become an expert in MEAN StackView Course
Full Stack Web Developer Course

Compile-Time vs. Run-Time Polymorphism in C++

The key differences between compile-time polymorphism and run-time polymorphism are summarised below:

COMPILE-TIME

RUN-TIME

Compile-time polymorphism is also known as static or early binding polymorphism.

Run-time polymorphism is also known as dynamic or late binding polymorphism.

The function calls are resolved by the compiler.

The function calls are not resolved by the compiler.

Compile-time polymorphism provides less flexibility to the programmers since everything is executed during compilation.

In contrast, run-time polymorphism is more flexible since everything is executed during run-time.

It can be implemented through function overloading and operator overloading.

It can be implemented through virtual functions and function overriding.

Method overloading is an application of compile-time polymorphism where the same name can be commissioned between more than one method of functions having different arguments or signatures and the same return types.

Method overriding is an application of run time polymorphism where two or more functions with the same name, arguments, and return type accompany different classes of the same structure.

This method has a much faster execution rate since all the methods that need to be executed are called during compile time.

This method has a comparatively slower execution rate since all the methods that need to be executed are called during the run time.

This method is less preferred for handling compound problems since all the methods and details come to light only during the compile time.

This method is known to be better for dealing with compound problems since all the methods and details turn up during the run time.

Are you a web developer or interested in building a website? Enroll for the Full Stack Web Developer - MEAN Stack Master's Program. Explore the course preview!

Final Thoughts

In this article, you have learned everything you need to know about polymorphism in C++. You saw the importance of polymorphism and why is it necessary for C++. This article dived deep into the uses, types, ways to implement it, and all other important and related concepts of polymorphism. You explored how to implement compile-time polymorphism using function overloading and operator overloading. You also saw how to implement run-time polymorphism using method overriding and virtual functions. 

To better understand the entire C++ programming language, you can go through our guide on C++ Programming for Beginners.

Why stop here? Leverage our course on Full Stack Web Development to learn trending technologies and skills and give yourself a chance to work for top tech giants. This course will walk you through complete end-to-end technologies/skills that will help you to set your foot into professional web development. These include Java, DevOps, Agility, HTML, AWS, etc.

Also, check out the complete list of free online courses by Simplilearn.

If you have any questions for us, please mention them in the comments section and we will have our experts answer them for you.

Happy Learning!

About the Author

SimplilearnSimplilearn

Simplilearn is one of the world’s leading providers of online training for Digital Marketing, Cloud Computing, Project Management, Data Science, IT, Software Development, and many other emerging technologies.

View More
  • Disclaimer
  • PMP, PMI, PMBOK, CAPM, PgMP, PfMP, ACP, PBA, RMP, SP, and OPM3 are registered marks of the Project Management Institute, Inc.