Module 18: Polymorphism in C++
Polymorphism is one of the four pillars of Object-Oriented Programming (OOP). The word polymorphism means "many forms." It allows the same interface (function or object) to behave differently depending on the context.
For example, a draw() function may draw a circle, rectangle, or triangle depending on the object that calls it.
Types of Polymorphism
- Compile-Time Polymorphism (Static Binding)
- Runtime Polymorphism (Dynamic Binding)
1. Compile-Time Polymorphism
Compile-time polymorphism is resolved by the compiler before the program runs.
It includes:
- Function Overloading
- Operator Overloading
2. Function Overloading
Function overloading allows multiple functions with the same name but different parameter lists.
Example
1#include <iostream> 2 3using namespace std; 4 5class Calculator 6{ 7public: 8 int add(int a, int b) 9 { 10 return a + b; 11 } 12 13 double add(double a, double b) 14 { 15 return a + b; 16 } 17 18 int add(int a, int b, int c) 19 { 20 return a + b + c; 21 } 22}; 23 24int main() 25{ 26 Calculator calc; 27 28 cout << calc.add(5, 10) << endl; 29 cout << calc.add(2.5, 3.5) << endl; 30 cout << calc.add(1, 2, 3); 31 32 return 0; 33}
Output
115 26 36
Advantages
- Improves code readability.
- Reuses function names.
- Supports different input types.
3. Operator Overloading
Operator overloading allows operators to work with user-defined objects.
Example
1#include <iostream> 2 3using namespace std; 4 5class Number 6{ 7public: 8 int value; 9 10 Number(int v) 11 { 12 value = v; 13 } 14 15 Number operator+(const Number& other) 16 { 17 return Number(value + other.value); 18 } 19}; 20 21int main() 22{ 23 Number n1(10); 24 Number n2(20); 25 26 Number result = n1 + n2; 27 28 cout << result.value; 29 30 return 0; 31}
Output
130
4. Runtime Polymorphism
Runtime polymorphism is achieved through inheritance and virtual functions.
The function that executes is determined while the program is running.
5. Virtual Function
A virtual function allows a derived class to override a base class function.
Example
1#include <iostream> 2 3using namespace std; 4 5class Animal 6{ 7public: 8 virtual void sound() 9 { 10 cout << "Animal Sound" << endl; 11 } 12}; 13 14class Dog : public Animal 15{ 16public: 17 void sound() 18 { 19 cout << "Dog Barks" << endl; 20 } 21}; 22 23int main() 24{ 25 Animal* animal = new Dog(); 26 27 animal->sound(); 28 29 delete animal; 30 31 return 0; 32}
Output
1Dog Barks
6. override Keyword
The override keyword ensures that a derived class correctly overrides a virtual function.
Example
1#include <iostream> 2 3using namespace std; 4 5class Animal 6{ 7public: 8 virtual void sound() 9 { 10 cout << "Animal"; 11 } 12}; 13 14class Dog : public Animal 15{ 16public: 17 void sound() override 18 { 19 cout << "Dog"; 20 } 21}; 22 23int main() 24{ 25 Dog d; 26 27 d.sound(); 28 29 return 0; 30}
Output
1Dog
If the function signature doesn't match the base class, the compiler reports an error.
7. final Keyword
The final keyword prevents further overriding or inheritance.
Prevent Function Overriding
1#include <iostream> 2 3using namespace std; 4 5class Animal 6{ 7public: 8 virtual void sound() final 9 { 10 cout << "Animal"; 11 } 12};
No derived class can override sound().
Prevent Class Inheritance
1class Animal final 2{ 3};
No class can inherit from Animal.
8. Pure Virtual Function
A pure virtual function has no implementation in the base class and forces derived classes to implement it.
Syntax
1virtual void display() = 0;
Example
1#include <iostream> 2 3using namespace std; 4 5class Shape 6{ 7public: 8 virtual void draw() = 0; 9}; 10 11class Circle : public Shape 12{ 13public: 14 void draw() override 15 { 16 cout << "Drawing Circle"; 17 } 18}; 19 20int main() 21{ 22 Circle c; 23 24 c.draw(); 25 26 return 0; 27}
Output
1Drawing Circle
9. Abstract Class
A class containing at least one pure virtual function is called an abstract class.
Characteristics:
- Cannot be instantiated.
- Used as a base class.
- Provides a common interface.
Example
1#include <iostream> 2 3using namespace std; 4 5class Vehicle 6{ 7public: 8 virtual void start() = 0; 9}; 10 11class Car : public Vehicle 12{ 13public: 14 void start() override 15 { 16 cout << "Car Started"; 17 } 18}; 19 20int main() 21{ 22 Car car; 23 24 car.start(); 25 26 return 0; 27}
Output
1Car Started
Compile-Time vs Runtime Polymorphism
| Compile-Time | Runtime |
|---|---|
| Resolved during compilation | Resolved during execution |
| Faster | Slightly slower |
| Function Overloading | Virtual Functions |
| Operator Overloading | Method Overriding |
| Static Binding | Dynamic Binding |
Best Practices
- Use function overloading for similar operations with different parameter types.
- Overload operators only when they make logical sense.
- Declare base class destructors as
virtualwhen using polymorphism. - Use the
overridekeyword to prevent accidental mistakes. - Use
finalonly when further inheritance or overriding should be prohibited. - Design interfaces using abstract classes and pure virtual functions.
Practice Problems
- Create overloaded functions to calculate the area of different shapes.
- Overload the
+operator for aComplexnumber class. - Create a base
Animalclass and override a virtualsound()function. - Demonstrate runtime polymorphism using base-class pointers.
- Create an abstract
Employeeclass with a pure virtualcalculateSalary()function. - Use the
overrideandfinalkeywords in an inheritance example.
Interview Questions
- What is polymorphism in C++?
- What are the types of polymorphism?
- What is compile-time polymorphism?
- What is runtime polymorphism?
- What is function overloading?
- What is operator overloading?
- What is a virtual function?
- Why should you use the
overridekeyword? - What is the purpose of the
finalkeyword? - What is a pure virtual function?
- What is an abstract class?
- Why is a virtual destructor important in polymorphic base classes?
Summary
In this module, you learned:
- The concept of polymorphism and its role in Object-Oriented Programming.
- How compile-time polymorphism is achieved through function and operator overloading.
- How runtime polymorphism uses virtual functions and dynamic binding.
- How the
overridekeyword improves code safety. - How the
finalkeyword prevents unwanted inheritance or overriding. - How pure virtual functions define interfaces.
- How abstract classes provide a common blueprint for derived classes.
Next Module: Module 19: Templates — Function Templates, Class Templates, Template Specialization, Variadic Templates, Non-Type Template Parameters, and Generic Programming.