Polymorphism is described as the concept of utilizing a function or an operator for multiple purposes. Essentially, it allows an operator or function to be utilized in various ways.
For example
Let's consider an operator '+' that is employed to sum two integer values and also to combine two strings.
Therefore, the '+' operator has dual functionality - performing addition and string concatenation.
Now we will explore the various forms of polymorphism present in C++.
Compile-time polymorphism
It is characterized by polymorphism where the function is invoked during compilation. This particular mechanism is also referred to as early or static binding.
Examples of compile-time polymorphism
1) Function overloading
Function overloading is the practice of using a single function for multiple functionalities. In this scenario, a function can execute various operations by altering its signature, including the number and types of arguments. This concept exemplifies compile-time polymorphism, where the determination of which function to invoke occurs during the compilation phase.
Example
In the following code snippet, we've defined a class named Addition which is responsible for adding numbers together and concatenating strings. Within this class, there is a method called ADD that has been overloaded twice.
The ADD(int X, int Y) function adds two integers, while the ADD function without any parameters concatenates strings.
#include <iostream>
using namespace std;
class Addition { // Create Addition class
public:
int ADD(int X, int Y) // Add function add two numbers
{
return X + Y; // return the Addition of two numbers
}
int ADD()
{ // this ADD function concatenates two strings
string a = "HELLO";
string b = " JAVACPPTUTORIAL";
string c = a + b; // concatenate two strings
cout << c << endl; // print result
}
};
int main(void)
{
Addition obj; // Object is created of Addition class
cout << obj.ADD(120, 105) << endl; //first method is called to add two integers
obj.ADD(); // second method is called to concatenate two strings
return 0;
}
Output
225
HELLO JAVACPPTUTORIAL
Operator Overloading
Operator overloading is described as utilizing an operator for addition functionality other than its default behavior.
The utilization of operator overloading is essential as it assigns specific functionalities to custom data types. One advantage of operator overloading is the ability to assign multiple operations to a single operand. An illustrative instance of operator overloading is the '+' operator, which can be employed for both numerical addition and string concatenation.
The operators , :: ?: sizeof cant be overloaded.
Example
In this instance, we have redefined the addition operator '+' to concatenate two strings.
An operator can be overloaded by employing the operator keyword along with the specific operator that is to be overloaded.
#include <bits/stdc++.h>
using namespace std;
class A // Create a class A
{
string x; // private data member x
public:
A() {}
A(string i)
{
x = i; // Assign the data member
}
void operator+(A); // operator overloading
};
void A::operator+(A a) // concetenate the strings and print output
{
string m = x + a.x;
cout << "The result of the addition of two objects is: " << m;
}
int main()
{
A a1("Welcome "); // string 1
A a2("to javacpptutorial"); // string 2
a1 + a2; // concetenate two strings using operator overloading
return 0;
}
Output
The result of the addition of two objects is: Welcome to javacpptutorial
Run-time polymorphism
Runtime polymorphism refers to the scenario where a function is invoked during the execution of a program.
An instance of runtime polymorphism is demonstrated through the concept of function overriding.
Function overriding
When a function is overridden, it indicates that a fresh implementation of that function is provided in the subclass. Consequently, function overriding involves having dual definitions, one in the superclass and the other in the subclass. The selection of which function to utilize occurs dynamically during runtime.
Example
In this specific scenario, the class "animal" contains a method f, which is also present in the subclass "Man". Executing the function f using an instance of the base class will display the base class contents, while using an instance of the derived class will show the derived class contents. As a result, the determination of which f function to execute is made during runtime.
#include <iostream>
using namespace std;
class Animal { // Create a new class
public:
void f()
{ // the function f will be overriden in the class Man
cout << "Eating..." << endl;
}
};
class Man : public Animal // Base class inheriting derived class
{
public:
void f() // The function f being overriden
{
cout << "Walking ..." << endl;
}
};
int main(void)
{
Animal A = Animal();
A.f(); //parent class object
Man m = Man();
m.f(); // child class object
return 0;
}
Output
Eating...
Walking ...