Understanding Polymorphism in C++: An Easy Guide.

Welcome to the engaging world of Polymorphism in C++! Imagine having a shape-shifting ability like a magical creature. In programming, polymorphism allows an object to take on multiple forms, just like transforming into different shapes. In this article, we’ll explore why we need polymorphism, what it is, and how we can use it in C++. Polymorphism enables us to write more flexible and extensible code, making it an essential concept for creating powerful and efficient programs. So let’s dive in and unlock the secrets of polymorphism together!

Why Do We Need Polymorphism in C++?

Polymorphism in C++ is like having a toolbox of different tools that can be used interchangeably. It allows us to write more flexible and adaptable code. Here’s why we need it in simpler terms:

  • Code Reusability: Polymorphism lets us create a single function or method that can work with multiple types of objects. This means we don’t need to write separate code for each type, making our codebase smaller and easier to manage.
  • Flexibility: With polymorphism, we can extend or modify our classes without changing the existing code. New classes can be added, and existing ones can be altered without affecting the parts of the code that use these classes.
  • Ease of Maintenance: Since polymorphism promotes code reuse and flexibility, maintaining the code becomes simpler. Changes and updates are localized, reducing the chances of introducing errors in other parts of the program.
  • Cleaner Code: Polymorphism encourages a cleaner and more organized code structure. Instead of writing many conditional statements for different cases, we can use a unified approach that works for various scenarios.
  • Adaptability: Polymorphism is especially useful when working with arrays or collections of objects. It enables us to treat all objects in a consistent manner, even if they are of different types.

What Is Polymorphism in C++?

Polymorphism in C++ is a powerful concept that allows different objects to be treated as instances of a common base class, even if they belong to derived classes. It enables the use of a single interface to represent multiple related classes. Think of it like a musical instrument – you can play different types of instruments (like guitar, piano) using the same musical notation (interface)

In simpler terms, polymorphism lets you perform similar actions on different types of objects through a common interface. It provides flexibility and reusability in code by allowing you to write functions that can work with a variety of objects that share a common base.

Understanding Polymorphism in C++: An Easy Guide.
Polymorphism in C++

Types of Polymorphism

  • Compile-time Polymorphism
  • Runtime Polymorphism

Compile-time Polymorphism

Compile-time polymorphism in C++ is a concept where the compiler determines which function to execute based on the context during the compile time itself. This is achieved through function overloading and operator overloading.

Function Overloading:

In function overloading, you can have multiple functions with the same name but different parameters. The compiler decides which function to call based on the number and types of arguments provided when the function is called.

For example:

C++
#include <iostream>
using namespace std;

class MathOperations {
public:
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }
};

int main() {
    MathOperations math;
    cout << math.add(5, 10) << endl;        // Calls int add(int a, int b)
    cout << math.add(3.14, 2.71) << endl;  // Calls double add(double a, double b)
    return 0;
}

Output:

C++
15
5.85

Explanation:

  • Class Definition: The code defines a class MathOperations with two overloaded functions named add. One function takes two integers as parameters, and the other takes two doubles.
  • Function Overloading: Compile-time polymorphism is achieved through function overloading. Both add functions have the same name but different parameter types, allowing the program to choose the correct version based on the arguments passed.
  • Creating Object: In the main function, an object of the MathOperations class, named math, is created.
  • Calling Integer Version: When calling math.add(5, 10), the integer version of the add function is invoked, returning the sum of 5 and 10, which is printed as 15.
  • Calling Double Version: When calling math.add(3.14, 2.71), the double version of the add function is invoked, returning the sum of 3.14 and 2.71, which is printed as 5.85.

Operator Overloading:

Operator overloading allows you to define how an operator should behave with user-defined data types. This makes code more intuitive and readable.

For example:

C++
#include <iostream>
using namespace std;

class Complex {
public:
    int real, imag;

    Complex operator + (const Complex& other) {
        Complex sum;
        sum.real = real + other.real;
        sum.imag = imag + other.imag;
        return sum;
    }
};

int main() {
    Complex num1, num2, result;
    num1.real = 3;
    num1.imag = 5;
    num2.real = 2;
    num2.imag = 8;

    result = num1 + num2;  // Calls Complex operator + (const Complex& other)
    cout << "Real part: " << result.real << ", Imaginary part: " << result.imag << endl;
    return 0;
}

Output:

C++
Real part: 5, Imaginary part: 13

Explanation:

  • Class Definition: The code defines a class named Complex that represents complex numbers with real and imaginary parts.
  • Operator Overloading: Inside the class, the + operator is overloaded to allow adding two complex numbers together. It takes another Complex object as a parameter and returns a new Complex object representing the sum.
  • Objects Creation: In the main function, three Complex objects (num1, num2, and result) are created to hold complex numbers.
  • Values Assignment: The real and imaginary parts of num1 and num2 are assigned values 3, 5, 2, and 8 respectively.
  • Sum Calculation & Output: The overloaded + operator is used to add num1 and num2, storing the result in result. The real and imaginary parts of the sum are then printed to the console, resulting in the output: “Real part: 5, Imaginary part: 13”.

Compile-time polymorphism provides flexibility and clarity in code, making it easier to understand the behavior of functions and operators for different data types or scenarios.

Runtime Polymorphism

Runtime polymorphism in C++ is a powerful concept that allows you to achieve different behaviors in a program based on the specific instance of an object being referred to. This is a key feature of object-oriented programming and is achieved through a mechanism called function overriding.

In simple terms, runtime polymorphism enables a subclass to provide a specific implementation of a method that is already defined in its superclass. This means that even though you have a reference to a superclass object, when you call a method, the actual implementation that gets executed is determined by the type of the subclass instance that the reference is pointing to.

Here’s how it works: You have a base class (superclass) with a virtual function, and then you have derived classes (subclasses) that override this virtual function with their own specific implementations. When you call this function through a pointer or reference to the base class, the overridden function of the derived class gets executed dynamically at runtime.

To achieve this, you need to use pointers or references along with the virtual keyword for the base class function and the override keyword in the derived class.

Here’s a simple example with code to illustrate:

C++
#include <iostream>
using namespace std;

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

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

int main() {
    Shape* s1 = new Shape();
    Shape* c1 = new Circle();

    s1->draw(); // Output: Drawing a shape
    c1->draw(); // Output: Drawing a circle

    delete s1;
    delete c1;

    return 0;
}

Output:

C++
Drawing a shape
Drawing a circle

Explanation:

  • Base Class with Virtual Function: The base class Shape contains a virtual function draw(), which allows derived classes to provide their own implementation of this function.
  • Derived Class Implementation: The derived class Circle overrides the virtual function draw() from the base class, providing a specific implementation for drawing a circle.
  • Pointers to Base Class: Pointers to the base class Shape can be used to point to objects of the derived class Circle, allowing a uniform way to handle different shape types.
  • Runtime Resolution: When the draw() method is called through a base class pointer, the actual method executed is determined at runtime based on the object’s type. This enables the program to decide at runtime which version of the draw() method to invoke.
  • Demonstration of Runtime Polymorphism: This entire process illustrates runtime polymorphism, where the exact method to be executed is determined dynamically at runtime, allowing for greater flexibility and extensibility in the code design.

A Problem to Solve

Polymorphism is a key concept in object-oriented programming that allows objects to be treated as instances of their parent class or interface, regardless of their actual derived types. In C++, there are two main types of polymorphism: compile-time (or static) polymorphism and run-time (or dynamic) polymorphism.

Here’s a problem that will guide students through both types.

Problem Statement:

You’re designing a simple geometry calculator. Your task is to implement both compile-time and run-time polymorphism to calculate the area of different geometric shapes.

  • Compile-Time Polymorphism: Use function overloading to calculate the area of a circle and a rectangle.
    • For a circle, the area is calculated as ( \pi \times \text{radius}^2 ).
    • For a rectangle, the area is calculated as ( \text{length} \times \text{width} ).
  • Run-Time Polymorphism: Use inheritance and virtual functions to calculate the area of different shapes.
    • Create a base class named Shape with a pure virtual function named area.
    • Derive two classes from Shape: Triangle and Square. Implement the area function in both derived classes.
    • For a triangle, the area is calculated as ( \frac{1}{2} \times \text{base} \times \text{height} ).
    • For a square, the area is calculated as ( \text{side} \times \text{side} ).

Requirements:

  • Implement function overloading for compile-time polymorphism.
  • Implement a base class with a virtual function and derive classes for run-time polymorphism.
  • Allow the user to enter the required parameters for each shape.
  • Calculate and print the area for each shape according to the user’s choice.

Hints:

  • For compile-time polymorphism, you’ll need to declare functions with the same name but different parameters.
  • For run-time polymorphism, remember to use the virtual keyword for the function in the base class and override it in the derived classes.

Expected Output:

The program should be able to ask the user for the shape type and its dimensions and print the calculated area based on the user’s input.

Examples of Using Polymorphism in C++

Example 1

C++
#include<iostream>
using namespace std;

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

class Lion : public Animal {
public:
    void speak() {
        cout << "The lion roars" << endl;
    }
};

class Tiger : public Animal {
public:
    void speak() {
        cout << "The tiger growls" << endl;
    }
};

int main() {
    Animal* animal1 = new Lion();
    Animal* animal2 = new Tiger();
    animal1->speak();
    animal2->speak();
    delete animal1;
    delete animal2;
    return 0;
}

Output:

C++
The lion roars
The tiger growls

Explanation:

  • The code defines a base class Animal with a virtual method named speak() that outputs “The animal makes a sound”.
  • The Lion and Tiger classes are derived from the Animal class and override the speak() method with their own specific sounds.
  • In the main function, two pointers of type Animal* are created, pointing to dynamically allocated objects of Lion and Tiger.
  • The speak() method is called on these objects through the pointers, resulting in the respective outputs for lion and tiger sounds.
  • Finally, the dynamically allocated objects are deleted using the delete keyword to free the memory.

Example 2

C++
#include<iostream>
using namespace std;

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

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

class Square : public Shape {
public:
    void draw() {
        cout << "Drawing a square" << endl;
    }
};

int main() {
    Shape* shape1 = new Circle();
    Shape* shape2 = new Square();
    shape1->draw();
    shape2->draw();
    delete shape1;
    delete shape2;
    return 0;
}

Output:

C++
Drawing a circle
Drawing a square

Explanation:

  • The code defines a base class Shape with a virtual method named draw() that outputs “Drawing a shape”.
  • The Circle and Square classes are derived from the Shape class and override the draw() method with their own specific drawing instructions.
  • In the main function, two pointers of type Shape* are created, pointing to dynamically allocated objects of Circle and Square.
  • The draw() method is called on these objects through the pointers, resulting in the respective outputs for drawing a circle and drawing a square.
  • Finally, the dynamically allocated objects are deleted using the delete keyword to free the memory.

The Pros and Cons of Using Polymorphism in C++

Pros of PolymorphismCons of Polymorphism
Enables code reusability and flexibilityCan lead to complex code if not used carefully
Allows creating a common interface for different classesSlight performance overhead due to virtual function calls
Supports dynamic binding during runtimeRequires a good understanding of inheritance and virtual functions
Facilitates easy addition of new subclasses without modifying existing codeEnables creating of more organized and manageable code
This can lead to complex code if not used carefullyMay increase the size of the executable
Enhances maintainability and extensibility of the code
Promotes cleaner and more intuitive designs
The Pros and Cons of Using Polymorphism in C++

Key Takeaways

  • Flexibility: Polymorphism allows objects to adapt and exhibit different behaviors in various contexts, enhancing adaptability within the code.
  • Code Reusability: By using a common interface for different classes, you can reuse code across various parts of the program, reducing redundancy.
  • Extensibility: Polymorphism promotes the ease of adding new classes and functions without altering existing code, making future expansions more manageable.
  • Organized Design: By enabling objects to be treated as instances of their parent class, polymorphism leads to a more organized and systematic code structure.
  • Dynamic Solutions: Leveraging both compile-time and run-time polymorphism fosters more dynamic and responsive software solutions, paving the way for efficient and tailored programming.

Conclusion

Polymorphism is like a super tool in C++. It lets you make your programs much cooler and more interactive. Think of it as a way to make different things do different tricks using the same commands. So, you don’t have to write separate instructions for each thing – just one set of commands can do a bunch of different stuff.

Learning how to use polymorphism is like getting a special skill that makes your programs more flexible and easy to manage. It’s like having a magic wand that lets your code adapt and change as needed. So, keep learning and practicing, and you’ll soon become a polymorphism master, making your programs do all sorts of amazing things!

FAQs

  • What is polymorphism in C++?
    Polymorphism in C++ is the ability of a message to be displayed in more than one form. It allows our objects to take on many forms.
  • Why do we use polymorphism in C++?
    We use polymorphism in C++ to make our programs more flexible and interactive. It allows our objects to behave differently depending on their context.
  • How do we use polymorphism in C++?
    We use polymorphism in C++ by declaring a function as ‘virtual’ in the base class and then overriding it in the derived class. The overridden function will be called based on the actual object type at runtime.
  • Can using polymorphism make code more confusing?
    Yes, if you use polymorphism incorrectly, it can lead to problems like runtime errors. It’s important to understand how polymorphism works and when to use it.
  • What are some examples of using polymorphism in C++?
    Some examples include using polymorphism to create different animal sounds or to draw different shapes.
Deepak Vishwakarma

Founder

RELATED Articles

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.