Welcome to The Coding College! In this tutorial, we’ll explore one of the most powerful features of object-oriented programming: Polymorphism. Polymorphism allows objects to take on many forms, enabling flexible and reusable code in C++.
What Is Polymorphism?
Polymorphism comes from the Greek words “poly” (many) and “morph” (forms). In C++, polymorphism allows you to define methods in a base class and override them in derived classes, enabling the same function call to behave differently depending on the object.
Types of Polymorphism in C++:
- Compile-time Polymorphism (Static)
- Achieved via function overloading and operator overloading.
- Run-time Polymorphism (Dynamic)
- Achieved via function overriding and pointers or references.
Compile-Time Polymorphism
1. Function Overloading
Function overloading allows multiple functions with the same name to perform different tasks based on parameter lists.
Example:
#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 add(int a, int b, int c) {
return a + b + c;
}
};
int main() {
Calculator calc;
cout << "Sum (int, int): " << calc.add(2, 3) << endl;
cout << "Sum (double, double): " << calc.add(2.5, 3.5) << endl;
cout << "Sum (int, int, int): " << calc.add(1, 2, 3) << endl;
return 0;
}
Output:
Sum (int, int): 5
Sum (double, double): 6
Sum (int, int, int): 6
2. Operator Overloading
C++ allows operators to be overloaded, enabling you to define custom behaviors for operators applied to objects.
Example:
#include <iostream>
using namespace std;
class Complex {
public:
double real, imag;
Complex(double r, double i) : real(r), imag(i) {}
// Overload the + operator
Complex operator+(const Complex& other) {
return Complex(real + other.real, imag + other.imag);
}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1(2.5, 3.5), c2(1.5, 2.5);
Complex c3 = c1 + c2; // Using overloaded +
c3.display();
return 0;
}
Output:
4 + 6i
Run-Time Polymorphism
Function Overriding
In run-time polymorphism, a base class pointer or reference is used to call a function overridden by a derived class.
Example:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() { // Virtual function
cout << "Animal makes a sound." << endl;
}
};
class Dog : public Animal {
public:
void sound() override {
cout << "Dog barks." << endl;
}
};
class Cat : public Animal {
public:
void sound() override {
cout << "Cat meows." << endl;
}
};
int main() {
Animal* animalPtr;
Dog dog;
Cat cat;
animalPtr = &dog;
animalPtr->sound(); // Calls Dog's sound()
animalPtr = &cat;
animalPtr->sound(); // Calls Cat's sound()
return 0;
}
Output:
Dog barks.
Cat meows.
Key Concepts in Run-Time Polymorphism
1. Virtual Functions
- Use the
virtual
keyword in the base class to enable overriding.
2. Dynamic Binding
- At runtime, the correct function is invoked based on the type of the object being pointed to.
3. Overriding
- The derived class provides its specific implementation of the base class method.
Real-Life Application of Polymorphism
Shape Example
Imagine a scenario where you are building a program for shapes, and different shapes (circle, rectangle, etc.) have unique ways of calculating area.
#include <iostream>
using namespace std;
class Shape {
public:
virtual void area() {
cout << "Calculating area of a shape." << endl;
}
};
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
void area() override {
cout << "Area of Circle: " << 3.14 * radius * radius << endl;
}
};
class Rectangle : public Shape {
double length, width;
public:
Rectangle(double l, double w) : length(l), width(w) {}
void area() override {
cout << "Area of Rectangle: " << length * width << endl;
}
};
int main() {
Shape* shape;
Circle circle(5);
Rectangle rectangle(4, 6);
shape = &circle;
shape->area(); // Circle's area
shape = &rectangle;
shape->area(); // Rectangle's area
return 0;
}
Output:
Area of Circle: 78.5
Area of Rectangle: 24
Advantages of Polymorphism
- Code Reusability: Base class functionality can be reused in derived classes.
- Flexibility: The same interface can represent different data types or behaviors.
- Ease of Maintenance: Easier to extend and maintain code.
Key Points to Remember
- Compile-time Polymorphism (function/operator overloading) is resolved at compile time.
- Run-time Polymorphism (function overriding with
virtual
) is resolved at runtime. - Always use base class pointers or references to achieve dynamic polymorphism.
- Use
virtual
andoverride
keywords carefully to avoid unintended behavior.
Explore More at The Coding College
Discover advanced concepts in C++ programming and expand your knowledge on topics like polymorphism, inheritance, and OOP principles at The Coding College.