Polymorphism is a core concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common base class. Polymorphism enables a single interface to represent different underlying forms (data types). The word "polymorphism" is derived from Greek, meaning "many shapes" or "many forms."
There are two main types of polymorphism in C++:
Achieved using function overloading and operator overloading. The decision about which function to call is made at compile time.
Achieved using inheritance and virtual functions.
The decision about which function to call is made at runtime, allowing for more flexible and extensible code.
Compile-time polymorphism is resolved during the compilation of the program. It is primarily achieved through function overloading and operator overloading.
Function overloading allows multiple functions with the same name to exist, as long as they have different parameter lists.
#include <iostream>
class Printer {
public:
void print(int i) {
std::cout << "Printing int: " << i << std::endl;
}
void print(double f) {
std::cout << "Printing float: " << f << std::endl;
}
void print(const std::string& s) {
std::cout << "Printing string: " << s << std::endl;
}
};
int main() {
Printer printer;
printer.print(10); // Calls print(int)
printer.print(3.14); // Calls print(double)
printer.print("Hello World"); // Calls print(const std::string&)
return 0;
}
Operator overloading allows you to define or change the behavior of operators for user-defined types.
#include <iostream>
class Complex {
public:
Complex(double r, double i) : real(r), imag(i) {}
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
void print() const {
std::cout << "(" << real << ", " << imag << ")" << std::endl;
}
private:
double real, imag;
};
int main() {
Complex c1(1.0, 2.0);
Complex c2(3.0, 4.0);
Complex c3 = c1 + c2; // Uses operator overloading
c3.print(); // Outputs: (4, 6)
return 0;
}
+
operator is overloaded for the Complex class to add two complex numbers. The correct operator function is resolved at compile time.Runtime polymorphism is achieved through inheritance and virtual functions. It allows you to call derived class methods through a base class pointer or reference, depending on the actual type of the object.
#include <iostream>
class Animal {
public:
virtual void speak() const {
std::cout << "Animal makes a sound." << std::endl;
}
};
class Dog : public Animal {
public:
void speak() const override {
std::cout << "Dog barks." << std::endl;
}
};
class Cat : public Animal {
public:
void speak() const override {
std::cout << "Cat meows." << std::endl;
}
};
void makeAnimalSpeak(const Animal& animal) {
animal.speak(); // Calls the appropriate speak() method based on the object type
}
int main() {
Dog dog;
Cat cat;
makeAnimalSpeak(dog); // Outputs: Dog barks.
makeAnimalSpeak(cat); // Outputs: Cat meows.
return 0;
}
virtual
in the Animal class, allowing it to be overridden in the derived classes.makeAnimalSpeak
is called, the correct speak function is invoked based on the actual type of the object, not the type of the reference (Animal&
).Polymorphism is widely used in designing flexible and maintainable systems. It allows developers to write code that can work with objects of different classes in a unified way, often enabling the open/closed principle (one of the SOLID principles), where code is open for extension but closed for modification.
Consider a graphical user interface (GUI) framework where different widgets (buttons, sliders, text boxes) can be drawn on the screen. Polymorphism allows you to treat all widgets uniformly, despite their differences.
#include <iostream>
#include <vector>
class Widget {
public:
virtual void draw() const = 0; // Pure virtual function
};
class Button : public Widget {
public:
void draw() const override {
std::cout << "Drawing a button." << std::endl;
}
};
class Slider : public Widget {
public:
void draw() const override {
std::cout << "Drawing a slider." << std::endl;
}
};
void render(const std::vector<Widget*>& widgets) {
for (const Widget* widget : widgets) {
widget->draw(); // Calls the appropriate draw() method
}
}
int main() {
Button button;
Slider slider;
std::vector<Widget*> widgets = {&button, &slider};
render(widgets); // Outputs: Drawing a button. Drawing a slider.
return 0;
}
Widget
is an abstract class with a pure virtual function draw.Button
and Slider
classes inherit from Widget
and override the draw function.Polymorphism is a fundamental concept in C++ and object-oriented programming, enabling developers to write more flexible and reusable code. By leveraging polymorphism, you can design systems that are more modular, easier to extend, and maintain.
Previous Page | Course Schedule | Course Content