Underlying Mechanism of Polymorphism
Introduction
Polymorphism is a core concept in object-oriented programming (OOP) that enables objects to be treated as instances of their parent classes, regardless of their actual type. This flexibility allows developers to write code that can work with objects of different classes, enhancing code reusability and maintainability. In C++, polymorphism is primarily achieved through virtual functions, which enable compile-time and run-time polymorphism.
Types of Polymorphism
Compile-Time Polymorphism
Compile-time polymorphism, also known as function overloading, occurs when multiple functions share the same name but differ in parameters. The compiler determines the correct function to call at compile time based on the arguments provided.
Example:
class Calculator {
public:
void add(int a, int b) { std::cout << "Addition: " << a << " + " << b << std::endl; }
void add(double a, double b) { std::cout << "Addition: " << a << " + " << b << std::endl; }
};
Calculator calc;
calc.add(2, 3); // Compile-time polymorphism: selects int overload
calc.add(2.5, 3.5); // Selects double overload
Run-Time Polymorphism
Run-time polymorphism, or dynamic binding, is achieved via virtual functions. The compiler does not resolve the function call at compile time but instead delegates the decision to the runtime execution engine.
Example:
class Animal {
public:
virtual void sound() = 0; // Pure virtual function
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void sound() override { std::cout << "Bhow Bhow!" << std::endl; }
};
class Cat : public Animal {
public:
void sound() override { std::cout << "Miao Miao!" << std::endl; }
};
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->sound(); // Bhow Bhow!
animal2->sound(); // Miao Miao!
delete animal1;
delete animal2;
return 0;
}
Implementation Details
Virtual Function Mechanism
To enable run-time polymorphism, a class must declare a virtual function with the virtual keyword. The function's implementation is stored in a vtable (virtual table), which is a table of function pointers. The vtable is automatically generated by the compiler for classes with virtual functions.
Key Concepts:
- Virtual Function Pointer (VFP): A pointer to the vtable is stored in the object's memory.
- vtable: Contains pointers to the virtual functions of a class.
- Virtual Destructor: Ensures proper cleanup of objects when destroyed, even if they are deleted through a base class pointer.
Class Design
A class with virtual functions must have a virtual function pointer in its memory. The compiler generates the vtable for such classes, and the vtable is initialized with the addresses of the virtual function implementations.
Example:
class Base {
public:
virtual void display() { std::cout << "Base class" << std::endl; }
virtual ~Base() = default;
};
class Derived : public Base {
public:
void display() override { std::cout << "Derived class" << std::endl; }
};
Example: Polymorphism in Practice
Scenario
A program needs to handle different types of animals (Dog, Cat, Bird) and their respective sounds.
Implementation
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() = 0;
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void sound() override { cout << "Bhow Bhow!" << endl; }
};
class Cat : public Animal {
public:
void sound() override { cout << "Miao Miao!" << endl; }
};
class Bird : public Animal {
public:
void sound() override { cout << "Squawk!" << endl; }
};
int main() {
Animal* animals[] = { new Dog(), new Cat(), new Bird() };
for (auto& animal : animals) {
animal->sound();
}
delete[] animals;
return 0;
}
Output
Bhow Bhow!
Miao Miao!
Squawk!
Conclusion
Polymorphism in C++ is a powerful mechanism that allows objects to be treated as instances of their parent classes, enabling flexible and scalable code. Through virtual functions and vtables, developers can achieve compile-time and run-time polymorphism, ensuring that objects of different classes can invoke the same method. Understanding the implementation details, such as virtual function pointers and vtable management, is essential for writing efficient and maintainable C++ code.