Polymorphism in C++ is a fundamental concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common base class. It enables a function, method, or operator to behave differently based on the object it is acting upon. The term “polymorphism” means “many forms,” and it allows the same interface to be used for different underlying forms (data types).
Types of Polymorphism
There are two Types of Polymorphism
1. Compile-time Polymorphism (Static Polymorphism)
This polymorphism is used in compile-time.
Function Overloading: Multiple functions can have the same name but different parameters (different type, number, or order of arguments).
#include <iostream>
using namespace std;
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
};
int main() {
Calculator cal; // Corrected class name and added semicolon
int result1 = cal.add(15, 20); // Define result as an integer
double result2 = cal.add(15.2, 20.5); // Define result as an double
cout << "add two normal interger value = " << result1 << "\n"; // Printing the result
cout << "add two decimal value = " << result2 << "\n"; // Printing the result
return 0;
}
Output:
add two decimal value = 35.7
Operator Overloading: The ability to redefine the way operators work for user-defined types (e.g., classes).
#include <iostream>
using namespace std;
class Calculator {
private:
int value; // Value to store the number
public:
// Constructor to initialize value
Calculator(int v = 0) : value(v) {}
// Overload the + operator to add two Calculator objects
Calculator operator+(const Calculator& other) {
// Create a new Calculator object that contains the sum of the values
return Calculator(this->value + other.value);
}
// Function to display the value
void display() const {
cout << "Value: " << value << endl;
}
};
int main() {
Calculator cal1(10), cal2(20);
// Use overloaded + operator to add two Calculator objects
Calculator result = cal1 + cal2;
// Display the result of addition
result.display(); // Should display Value: 30
return 0;
}
Explanation:
- Operator Overloading: We overload the + operator for the Calculator class by defining a function operator+. This function takes another Calculator object and returns a new Calculator object that holds the sum of the value of both objects.
- Constructor: The constructor Calculator(int v = 0) is used to initialize the value.
- Display Function: display() is used to print the value stored inside a Calculator object.
- In main(), we create two Calculator objects (cal1 and cal2), use the overloaded + operator to add them, and then print the result.
Output:
2. Run-time Polymorphism (Dynamic Polymorphism)
This type of polymorphism is resolved at runtime, which requires the use of inheritance and virtual functions.
The key idea is that a base class reference (or pointer) can point to objects of derived classes, and the appropriate method is called based on the actual object type, not the type of the reference.
#include <iostream>
using namespace std;
class Shape {
public:
// Virtual function to be overridden by derived classes
virtual void draw() {
cout << "Drawing Shape\n";
}
// Virtual destructor for proper cleanup in case of polymorphism
virtual ~Shape() {
cout << "Shape Destructor\n";
}
};
class Circle : public Shape {
public:
// Override the draw function in the derived class
void draw() override {
cout << "Drawing Circle\n";
}
// Destructor for the derived class
~Circle() override {
cout << "Circle Destructor\n";
}
};
class Square : public Shape {
public:
// Override the draw function in the derived class
void draw() override {
cout << "Drawing Square\n";
}
// Destructor for the derived class
~Square() override {
cout << "Square Destructor\n";
}
};
int main() {
// Create base class pointer
Shape* shape1 = new Circle(); // Point to Circle object
Shape* shape2 = new Square(); // Point to Square object
// Call draw function. It will call the appropriate function based on the object type.
shape1->draw(); // Output: Drawing Circle
shape2->draw(); // Output: Drawing Square
// Delete the objects (virtual destructors will be called automatically)
delete shape1;
delete shape2;
return 0;
}
Explanation:
- draw() is a virtual function in the base class Shape. This means derived classes can override this function to provide their own behavior.
- virtual ~Shape() is a virtual destructor. Virtual destructors are important when using pointers to base class objects, as they ensure that the destructors of derived classes are called properly (avoiding memory leaks).
- Both Circle and Square classes override the draw() function to provide their own implementation.
Output:
Drawing Square
Circle Destructor
Shape Destructor
Square Destructor
Shape Destructor
Advantages of Polymorphism
Code Reusability: It allows one function to be reused for different types of objects.
Extensibility: You can add new derived classes without modifying the base class code.
Flexibility: It lets you treat different types of objects in a uniform way, simplifying code.