C++ Polymorphism

Welcome to The Coding College! In this tutorial, we’ll explore one of the most powerful features of object-oriented programming: Polymorphism. Polymorphism allows objects to take on many forms, enabling flexible and reusable code in C++.

What Is Polymorphism?

Polymorphism comes from the Greek words “poly” (many) and “morph” (forms). In C++, polymorphism allows you to define methods in a base class and override them in derived classes, enabling the same function call to behave differently depending on the object.

Types of Polymorphism in C++:

  1. Compile-time Polymorphism (Static)
    • Achieved via function overloading and operator overloading.
  2. Run-time Polymorphism (Dynamic)
    • Achieved via function overriding and pointers or references.

Compile-Time Polymorphism

1. Function Overloading

Function overloading allows multiple functions with the same name to perform different tasks based on parameter lists.

Example:

#include <iostream>
using namespace std;

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

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

    int add(int a, int b, int c) {
        return a + b + c;
    }
};

int main() {
    Calculator calc;
    cout << "Sum (int, int): " << calc.add(2, 3) << endl;
    cout << "Sum (double, double): " << calc.add(2.5, 3.5) << endl;
    cout << "Sum (int, int, int): " << calc.add(1, 2, 3) << endl;

    return 0;
}

Output:

Sum (int, int): 5  
Sum (double, double): 6  
Sum (int, int, int): 6  

2. Operator Overloading

C++ allows operators to be overloaded, enabling you to define custom behaviors for operators applied to objects.

Example:

#include <iostream>
using namespace std;

class Complex {
public:
    double real, imag;

    Complex(double r, double i) : real(r), imag(i) {}

    // Overload the + operator
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }

    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(2.5, 3.5), c2(1.5, 2.5);
    Complex c3 = c1 + c2; // Using overloaded +
    c3.display();

    return 0;
}

Output:

4 + 6i  

Run-Time Polymorphism

Function Overriding

In run-time polymorphism, a base class pointer or reference is used to call a function overridden by a derived class.

Example:

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void sound() { // Virtual function
        cout << "Animal makes a sound." << endl;
    }
};

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

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

int main() {
    Animal* animalPtr;

    Dog dog;
    Cat cat;

    animalPtr = &dog;
    animalPtr->sound(); // Calls Dog's sound()

    animalPtr = &cat;
    animalPtr->sound(); // Calls Cat's sound()

    return 0;
}

Output:

Dog barks.  
Cat meows.  

Key Concepts in Run-Time Polymorphism

1. Virtual Functions

  • Use the virtual keyword in the base class to enable overriding.

2. Dynamic Binding

  • At runtime, the correct function is invoked based on the type of the object being pointed to.

3. Overriding

  • The derived class provides its specific implementation of the base class method.

Real-Life Application of Polymorphism

Shape Example

Imagine a scenario where you are building a program for shapes, and different shapes (circle, rectangle, etc.) have unique ways of calculating area.

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void area() {
        cout << "Calculating area of a shape." << endl;
    }
};

class Circle : public Shape {
    double radius;

public:
    Circle(double r) : radius(r) {}

    void area() override {
        cout << "Area of Circle: " << 3.14 * radius * radius << endl;
    }
};

class Rectangle : public Shape {
    double length, width;

public:
    Rectangle(double l, double w) : length(l), width(w) {}

    void area() override {
        cout << "Area of Rectangle: " << length * width << endl;
    }
};

int main() {
    Shape* shape;

    Circle circle(5);
    Rectangle rectangle(4, 6);

    shape = &circle;
    shape->area(); // Circle's area

    shape = &rectangle;
    shape->area(); // Rectangle's area

    return 0;
}

Output:

Area of Circle: 78.5  
Area of Rectangle: 24  

Advantages of Polymorphism

  1. Code Reusability: Base class functionality can be reused in derived classes.
  2. Flexibility: The same interface can represent different data types or behaviors.
  3. Ease of Maintenance: Easier to extend and maintain code.

Key Points to Remember

  1. Compile-time Polymorphism (function/operator overloading) is resolved at compile time.
  2. Run-time Polymorphism (function overriding with virtual) is resolved at runtime.
  3. Always use base class pointers or references to achieve dynamic polymorphism.
  4. Use virtual and override keywords carefully to avoid unintended behavior.

Explore More at The Coding College

Discover advanced concepts in C++ programming and expand your knowledge on topics like polymorphism, inheritance, and OOP principles at The Coding College.

Leave a Comment