Introduction to Polymorphism in C++


Polymorphism is one of the core concepts of Object-Oriented Programming (OOP) in C++. It allows objects of different classes to be treated as objects of a common base class. The most important feature of polymorphism is that it enables a single function or method to operate on different types of objects in different ways. Polymorphism in C++ can be categorized into two types: compile-time polymorphism and runtime polymorphism.

Types of Polymorphism

  • Compile-time Polymorphism: This type of polymorphism is resolved during the compile time. Function overloading and operator overloading are examples of compile-time polymorphism.
  • Runtime Polymorphism: This type of polymorphism is resolved at runtime. It is achieved using function overriding and virtual functions.

Compile-time Polymorphism

Compile-time polymorphism is achieved by function overloading and operator overloading. The function or operator is bound to the object at compile time, based on the type of arguments passed to the function or operator.

Example of Function Overloading

Function overloading allows multiple functions with the same name but different parameter lists to coexist. The correct function is selected at compile time based on the number or types of arguments.

    #include <iostream>

    class Printer {
    public:
        void print(int i) {
            std::cout << "Printing integer: " << i << std::endl;
        }

        void print(double d) {
            std::cout << "Printing double: " << d << std::endl;
        }

        void print(const char* str) {
            std::cout << "Printing string: " << str << std::endl;
        }
    };

    int main() {
        Printer printer;
        printer.print(10);           // Calls print(int)
        printer.print(3.14);         // Calls print(double)
        printer.print("Hello!");     // Calls print(const char*)
        return 0;
    }
        

Output:

    Printing integer: 10
    Printing double: 3.14
    Printing string: Hello!
        

Runtime Polymorphism

Runtime polymorphism is achieved through function overriding and virtual functions. This allows a function in a derived class to have the same name and signature as a function in the base class, but the function in the derived class is executed at runtime based on the type of object being referred to.

Example of Function Overriding

In function overriding, a derived class provides a specific implementation of a function that is already defined in the base class. The base class function should be declared as virtual to allow dynamic dispatch at runtime.

    #include <iostream>

    class Animal {
    public:
        virtual void sound() {
            std::cout << "Animal makes a sound" << std::endl;
        }
    };

    class Dog : public Animal {
    public:
        void sound() override {
            std::cout << "Dog barks" << std::endl;
        }
    };

    class Cat : public Animal {
    public:
        void sound() override {
            std::cout << "Cat meows" << std::endl;
        }
    };

    int main() {
        Animal* animal1 = new Dog();
        Animal* animal2 = new Cat();
        
        animal1->sound();   // Calls Dog's sound() method
        animal2->sound();   // Calls Cat's sound() method

        delete animal1;
        delete animal2;
        return 0;
    }
        

Output:

    Dog barks
    Cat meows
        

Explanation

In the example above, the sound() method is overridden in the derived classes Dog and Cat. At runtime, even though the object is referenced by a pointer of type Animal, the correct function (based on the actual object type) is called. This is runtime polymorphism, enabled by the use of the virtual keyword in the base class.

Virtual Functions

In C++, a function can be made virtual in the base class using the virtual keyword. When a function is virtual, C++ determines which function to call at runtime, based on the type of the object being pointed to, not the type of the pointer. This is known as dynamic dispatch.

Example of Virtual Functions

    #include <iostream>

    class Shape {
    public:
        virtual void draw() {
            std::cout << "Drawing a shape" << std::endl;
        }
    };

    class Circle : public Shape {
    public:
        void draw() override {
            std::cout << "Drawing a circle" << std::endl;
        }
    };

    class Rectangle : public Shape {
    public:
        void draw() override {
            std::cout << "Drawing a rectangle" << std::endl;
        }
    };

    int main() {
        Shape* shape1 = new Circle();
        Shape* shape2 = new Rectangle();

        shape1->draw();   // Calls Circle's draw() method
        shape2->draw();   // Calls Rectangle's draw() method

        delete shape1;
        delete shape2;
        return 0;
    }
        

Output:

    Drawing a circle
    Drawing a rectangle
        

Conclusion

Polymorphism in C++ allows you to write flexible and reusable code by enabling different classes to share the same interface. It provides a way to call derived class functions through base class pointers or references, making it an essential concept for achieving runtime flexibility and dynamic behavior in object-oriented programming. By using virtual functions and function overriding, C++ supports runtime polymorphism, and compile-time polymorphism is achieved through function overloading and operator overloading.





Advertisement