Polymorphism in C++

This article covers polymorphism and its types in C++ with examples. Let’s start!!!

What is Polymorphism?

The literal meaning of Polymorphism is to have many forms. In programming, this means that the same entity acts in different ways depending on situations. Polymorphism is a key concept of OOPs.

Consider yourself as a real life example of polymorphism. Depending on situations, you perform different roles like a student, a son/daughter, a brother/sister, etc.

Types of Polymorphism in C++

There are two types of polymorphism in C++:

1. Compile-time Polymorphism in C++

This type of polymorphism is also referred to as static binding or early binding. It takes place during compilation.
We use function overloading and operator overloading to achieve compile-time polymorphism.

a. Function Overloading in C++

In C++, two or more functions can have the same name if the number and/or type of parameters are different, this is called function overloading. Thus, overloaded functions are functions that have the same name but different parameters.

An overloaded function is called based on the number and type of parameters passed. Thus, the compiler picks the correct function during compilation of the program.

Examples of overloaded functions

int add(int, int);
int add(int, int, int);		//number of parameters different
double add(double, double);		//type of parameters different

Example to illustrate function overloading in C++

#include <iostream>
using namespace std;

int add(int a, int b) {
    return a+b;
}

int add(int a, int b, int c) {
    return a+b+c;
}

double add(double a, double b) {
    return a+b;
}

int main() {
  int x = 3, y = 7, z = 12;
  double n1 = 4.56, n2 = 13.479;
  
  cout<<"x+y = "<<add(x,y)<<endl;
  cout<<"x+y+z = "<<add(x,y,z)<<endl;
  cout<<"n1+n2 = "<<add(n1,n2);
  
  return 0;
}

Output

x+y = 10
x+y+z = 22
n1+n2 = 18.039
b. Operator Overloading in C++

We can also overload operators in C++. We can change the behavior of operators for user-defined types like objects and structures.

For example, the ‘+’ operator, used for addition, can also be used to concatenate two strings of std::string class. Its behavior will depend on the operands.

Example of Operator Overloading in C++

//Using + operator to add complex numbers
#include <iostream>
using namespace std;

class complex {
    private:
    float real, imag;
    public:
    complex(float r=0, float i=0){
        real = r;
        imag = i;
    }
    complex operator + (complex const &obj) {
        complex result;
        result.real = real + obj.real;
        result.imag = imag + obj.imag;
        return result;
    }
    void display() {
        cout<<real<<"+i"<<imag<<endl;
    }
};

int main() {
  complex c1(12.4,6), c2(7.9,8);
  complex c3 = c1 + c2;
  c3.display();
  return 0;
}

Output

20.3+i14

2. Run-time Polymorphism in C++

Run-time polymorphism takes place when functions are invoked during run time. It is also known as dynamic binding or late binding. Function overriding is used to achieve run-time polymorphism.

a. Function Overriding in C++

When a member function of a base class is redefined in its derived class with the same parameters and return type, it is called function overriding in C++. The base class function is said to be overridden.

The function call is resolved during run time and not by the compiler.

Example to illustrate function overriding in C++

#include <iostream>
using namespace std;

class base {
    public:
    virtual void display() {
        cout<<"Function of base class"<<endl;
    }
};
class derived : public base {
    public:
    void display() {
        cout<<"Function of derived class"<<endl;
    }
};

int main() {
  derived d1;
  d1.display();
  return 0;
}

Output

Function of derived class

Virtual Function in C++

A virtual function is a function defined in the base class with virtual keyword. The purpose of virtual function is to ensure that the function is overridden.

If we do not use virtual keyword with the base class function, it may not be overridden. We can still access it using a base class pointer. If the base class pointer points to the derived class object, the base class function will get executed.

Let’s see an example to understand this.

Example to illustrate the need of virtual function for function overriding in C++

#include <iostream>
using namespace std;

class base {
    public:
    void display() {
        cout<<"Function of base class"<<endl;
    }
};
class derived : public base {
    public:
    void display() {
        cout<<"Function of derived class"<<endl;
    }
};

int main() {
  derived d;
  base *b = &d;   //base class pointer
  b->display();   //base class function executes
  return 0;
}

Output

Function of base class

Example of run-time polymorphism using two derived classes

#include <iostream>
using namespace std;

class Polygon {
    public:
    virtual void show() {
        cout<<"Its a polygon"<<endl;
    }
};
class Triangle : public Polygon {
    public:
    void show() {
        cout<<"Triangle is 3 sided polygon"<<endl;
    }
};
class Rectangle : public Polygon {
    public:
    void show() {
        cout<<"Rectangle is 4 sided polygon"<<endl;
    }
};

int main() {
  Polygon *p;
  Triangle t;
  Rectangle r;
  p = &t;
  p->show();
  p = &r;
  p->show();
  return 0;
}

Output

Triangle is 3 sided polygon
Rectangle is 4 sided polygon

Run-time Polymorphism with Data Members

Run-time polymorphism can also be achieved through data members.

Example of run-time polymorphism with data members

#include <iostream>
#include <string>
using namespace std;

class Animal {
    public:
    string name = "Animal";
};
class Dog : public Animal {
    public:
    string name = "Dog";
};

int main() {
  Dog d;
  cout<<d.name;
  return 0;
}

Output

Dog

C++ Compile-time Polymorphism vs Run-time Polymorphism

Compile-time Polymorphism Run-time Polymorphism
Also called static or early binding. Also called dynamic or late binding.
Achieved through overloading. Achieved through overriding.
The function to be executed is known during compile time. The function to be executed is known during run time.
Faster is execution. Slow in execution.
Provides less flexibility. Provides more flexibility.

Summary

In this article, we learnt about polymorphism in C++. There are two types of polymorphism in C++, compile-time and run-time polymorphism. Function overloading and operator overloading are used to achieve compile-time polymorphism.

Function overriding is used to achieve run-time polymorphism. We learnt these with the use of suitable examples. We also understood the need of virtual functions for function overriding. Lastly, we listed the differences in the two types of polymorphism.