Previous chapter: Chapter 11: Inheritance: Building Class Hierarchies in C++
Polymorphism (meaning "many forms") is the third pillar of OOP and one of C++'s most important features. It allows a single interface to represent multiple underlying forms of objects, enabling highly flexible and extensible code.
1. Understanding Polymorphism
In C++, polymorphism is achieved mainly through method overriding combined with pointers or references to the base class.
Static vs. Dynamic Polymorphism
Static Polymorphism (Compile-time): Handled by the compiler (e.g., function overloading, covered in Chapter 5).
Dynamic Polymorphism (Run-time): Handled during program execution, achieved using the virtual keyword.
2. The virtual Keyword and Dynamic Dispatch
When you have a pointer to a base class that holds the address of a derived class object, calling an overridden method usually defaults to the Base Class version. The virtual keyword fixes this.
By declaring a base class function as virtual, you enable dynamic dispatch. This means that when the function is called via a base class pointer or reference, C++ looks up the object's actual type at runtime and executes the correct Derived Class version.
class Shape {
public:
virtual void draw() { // Declared as virtual
std::cout << "Drawing a generic shape." << std::endl;
}
};
class Circle : public Shape {
public:
void draw() override { // The 'override' keyword is a C++ safety feature
std::cout << "Drawing a Circle." << std::endl;
}
};
int main() {
Shape* s_ptr = new Circle(); // Pointer to Base, pointing to Derived
s_ptr->draw(); // Output: Drawing a Circle. (Dynamic Dispatch)
delete s_ptr;
return 0;
}
3. Pure Virtual Functions and Abstract Classes
Sometimes, a Base Class is too general to have a meaningful implementation for a certain function (e.g., the draw() function in the Shape class).
Pure Virtual Functions
A pure virtual function is a virtual function declared by assigning $0$ to it. It forces any derived concrete class to provide its own implementation.
virtual void calculate_area() = 0; // Pure virtual function
Abstract Classes
Any class containing at least one pure virtual function is an Abstract Class.
You cannot create objects of an abstract class.
Abstract classes serve only as interfaces, providing a common contract for derived classes to follow.
A derived class must implement all inherited pure virtual functions to become a concrete (non-abstract) class that can be instantiated.
4. Virtual Destructors
If a class uses dynamic memory (Chapter 7) and is intended to be used as a Base Class for polymorphism, its destructor must be declared virtual. Failing to do so can lead to an incorrect cleanup, causing memory leaks when deleting a derived object via a base class pointer.