5.3) Polymorphism in C++

What is Polymorphism?

Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects of different classes to be treated as objects of a common base class. It enables you to write code that can work with objects of multiple types in a unified way, providing flexibility and extensibility in your programs.

At its core, polymorphism allows you to:

  1. Treat objects of different derived classes as objects of a common base class.
  2. Call methods on these objects through pointers or references to the base class, and the appropriate method implementation is determined at runtime based on the actual object type.

There are two main types of polymorphism: compile-time polymorphism and runtime polymorphism.

1. Compile-Time Polymorphism


Also known as static polymorphism, this occurs when the method to be called is determined at compile time. It is achieved through function overloading and operator overloading. In function overloading, different functions with the same name but different parameter lists are defined, and the appropriate function is selected based on the arguments provided during the function call.

2. Runtime Polymorphism


Also known as dynamic polymorphism, this occurs when the method to be called is determined at runtime. It is achieved through function overriding and is closely related to inheritance and virtual functions. In runtime polymorphism, a base class reference or pointer can be used to refer to objects of derived classes, and the appropriate method implementation is selected based on the actual object type.

Runtime polymorphism is the more common form of polymorphism and is a central concept in OOP. It enables the creation of flexible and extensible code by allowing objects of different types to be treated uniformly through their common base class.

Here’s a high-level overview of how runtime polymorphism works:

  1. The base class defines a virtual function.
  2. The derived classes override the virtual function with their own specific implementations.
  3. When a base class reference or pointer is used to call the virtual function on an object, the appropriate implementation is chosen based on the actual object type.

Polymorphism plays a vital role in designing modular and maintainable software systems. It allows you to create code that is adaptable to new types of objects without requiring significant modifications to the existing codebase.

Compile-time polymorphism vs Runtime polymorphism

Here’s a comparison of compile-time polymorphism (static polymorphism) and runtime polymorphism (dynamic polymorphism):

AspectCompile-Time Polymorphism (Static Polymorphism)Runtime Polymorphism (Dynamic Polymorphism)
Method ResolutionDetermined at compile timeDetermined at runtime
MechanismFunction overloading, operator overloadingFunction overriding
BindingEarly binding (static binding)Late binding (dynamic binding)
Object TypeKnown at compile timeKnown at runtime
Use CasesKnown set of methods with different parametersInheritance and varying implementations
FlexibilityLimited flexibility in method invocationHigh flexibility in method invocation
PerformanceGenerally faster due to early bindingSlightly slower due to late binding
Virtual FunctionsNot used in compile-time polymorphismCore concept; requires virtual functions
Base Class Pointer/ReferenceNot commonly usedCommonly used for accessing derived class methods
Code SizeOften results in larger code sizeMore efficient memory usage

Both compile-time polymorphism and runtime polymorphism have their own advantages and use cases. Compile-time polymorphism is useful when you have a known set of methods with different parameter lists, and it’s determined at compile time which method to call based on the parameters provided. Runtime polymorphism is more flexible and dynamic, allowing you to work with objects of different types through a common interface. It’s achieved through function overriding and is particularly useful in scenarios involving inheritance and varying implementations of methods.

The choice between compile-time and runtime polymorphism depends on the specific requirements of your program and the design goals you are aiming to achieve.

Benefits of Polymorphism

  • Unified interface: Different objects can be treated uniformly using the same base class interface.
  • Extensibility: Adding new derived classes does not require changes to the code that uses polymorphism.
  • Code reusability: Common behaviors can be defined in the base class, and derived classes can provide specific implementations.
  • Flexible design: Polymorphism allows you to write more flexible and adaptable code that can handle various object types.

Example of Polymorphism in C++

Let’s delve into a detailed explanation of polymorphism in C++ with code examples to illustrate the concept.

1. Base Class and Derived Classes


We’ll start by defining a base class Shape and two derived classes Circle and Rectangle.

#include <iostream>

class Shape {
public:
    virtual void display() {
        std::cout << "This is a shape." << std::endl;
    }
};

class Circle : public Shape {
public:
    void display() override {
        std::cout << "This is a circle." << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void display() override {
        std::cout << "This is a rectangle." << std::endl;
    }
};

2. Polymorphism in Action


We’ll use polymorphism to create an array of pointers to the base class type, and these pointers can point to objects of various derived classes.

int main() {
    Shape* shapes[3];

    Circle circle;
    Rectangle rectangle;

    shapes[0] = &circle;
    shapes[1] = &rectangle;
    shapes[2] = new Circle();

    for (int i = 0; i < 3; ++i) {
        shapes[i]->display(); // Calls the appropriate overridden function based on the object type
    }

    delete shapes[2]; // Deleting dynamically allocated object

    return 0;
}

Output:

This is a circle.
This is a rectangle.
This is a circle.

In this example:

  • The base class Shape has a virtual function display().
  • The derived classes Circle and Rectangle override the display() function.
  • An array of pointers to the Shape class is created, holding pointers to objects of different derived classes.
  • During the loop, the display() function is called on each object through the pointers, and the appropriate overridden version is executed based on the actual object type. This is known as runtime polymorphism.

Leave a Reply