OOP/OOD  

Chapter 12: Polymorphism: Virtual Functions and Abstract Classes in C++

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.