Polymorphism In C++

Polymorphism in C++ refers to the ability of different objects to respond in different ways to the same function call. This allows for flexibility and versatility in programming.

Polymorphism is a powerful tool that can be used to create flexible and reusable code. It is one of the fundamental concepts of object-oriented programming.

Classification Of Polymorphism

  • Compile-time Polymorphism
  • Runtime Polymorphism

Compile Time Polymorphism

Compile-time Polymorphism: Also known as static polymorphism or early binding polymorphism, it is achieved at compile time and is based on function overloading and operator overloading. Function overloading allows multiple functions with the same name but different parameters to be defined within the same scope. Operator overloading enables the redefinition of operators to work with user-defined types.

Function Overloading

Function overloading allows multiple functions with the same name but different parameters to be defined within the same scope. The compiler determines which function to call based on the number and types of arguments passed during the function call.

#include <iostream>
using namespace std;
 
// Function to calculate the area of a square
int area(int side) {
    return side * side;
}
 
// Function to calculate the area of a rectangle
int area(int length, int width) {
    return length * width;
}
 
int main() {
    cout << "Area of square: " << area(5) << endl;          // Calls area(int)
    cout << "Area of rectangle: " << area(4, 6) << endl;    // Calls area(int, int)
    return 0;
}

Output:

Area of square: 25
Area of rectangle: 24

Explanation:

  • area(5) calculates the area of a square with a side length of 5 units. It calls the area(int side) function and returns 25.
  • area(4, 6) calculates the area of a rectangle with length 4 units and width 6 units. It calls the area(int length, int width) function and returns 24.

Operator Overloading

Operator overloading allows operators to be redefined for user-defined types. This means that operators such as +, -, *, /, etc., can be used with objects of a class in addition to built-in types.

However, not all operators can be overloaded. Operators such as . (dot), :: (scope resolution), ?: (ternary conditional), and sizeof cannot be overloaded.

#include <iostream>
using namespace std;
 
// Class representing a complex number
class Complex {
private:
    float real;
    float imag;
 
public:
    // Constructor
    Complex(float r = 0.0, float i = 0.0) {
        real = r;
        imag = i;
    }
 
    // Overloading + operator to add two complex numbers
    Complex operator+(Complex &obj) {
        Complex temp;
        temp.real = real + obj.real;
        temp.imag = imag + obj.imag;
        return temp;
    }
 
    // Display function
    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};
 
int main() {
    Complex c1(3.0, 4.0);
    Complex c2(1.0, 2.0);
    Complex sum = c1 + c2;  // Calls overloaded + operator
    cout << "Sum: ";
    sum.display();
    return 0;
}

Output:

Sum: 4 + 6i

Explanation:

  • Complex c1(3.0, 4.0); and Complex c2(1.0, 2.0); create two complex numbers: c1 with real part 3.0 and imaginary part 4.0, and c2 with real part 1.0 and imaginary part 2.0.
  • Complex sum = c1 + c2; adds the complex numbers c1 and c2 using the overloaded + operator, resulting in a new complex number sum.
  • The display() function is called to print the sum, which outputs the sum of the real parts and imaginary parts as "Sum: 4 + 6i".

Runtime Polymorphism

Also known as dynamic polymorphism or late binding polymorphism, it is achieved at runtime and is based on function overriding and virtual functions. Function overriding occurs when a derived class provides a specific implementation for a function that is already defined in its base class. Virtual functions are functions declared in a base class with the virtual keyword, allowing them to be overridden in derived classes. The appropriate function to be executed is determined dynamically at runtime based on the object's actual type.

Function Overriding

Function overriding occurs when a derived class provides a specific implementation for a function that is already defined in its base class. The function signatures (names and parameters) must match exactly between the base and derived classes for overriding to occur.

#include <iostream>
using namespace std;
 
// Base class
class Animal {
public:
    // Base class function
    void makeSound() {
        cout << "Animal makes a generic sound" << endl;
    }
};
 
// Derived class
class Dog : public Animal {
public:
    // Derived class function overriding the base class function
    void makeSound() {
        cout << "Dog barks" << endl;
    }
};
 
int main() {
    Animal animalObj;
    Dog dogObj;
 
    // Calling makeSound() on base class object
    animalObj.makeSound(); // Output: Animal makes a generic sound
 
    // Calling makeSound() on derived class object
    dogObj.makeSound(); // Output: Dog barks
 
    return 0;
}

Output:

Animal makes a generic sound
Dog barks

Explanation:

  • In this code, we have a base class Animal with a member function makeSound().
  • We also have a derived class Dog that inherits from Animal.
  • The Dog class overrides the makeSound() function of the base class with its own implementation.
  • In the main() function, we create objects of both the base class Animal and the derived class Dog.
  • When we call the makeSound() function on each object, the appropriate implementation based on the object's type is executed.
  • This demonstrates function overriding, where the derived class function replaces the base class function with the same name.

Virtual Function

A virtual function is a member function in a base class that is declared with the virtual keyword. Virtual functions are meant to be overridden by derived classes. When a derived class overrides a virtual function, it provides its own implementation of the function.

#include <bits/stdc++.h>
using namespace std;
 
// Base class
class base {
public:
    // Virtual function
    virtual void print() {
        cout << "print base class" << endl;
    }
 
    // Non-virtual function
    void show() {
        cout << "show base class" << endl;
    }
};
 
// Derived class
class derived : public base {
public:
    // Overridden virtual function
    void print() {
        cout << "print derived class" << endl;
    }
 
    // Non-virtual function
    void show() {
        cout << "show derived class" << endl;
    }
};
 
// Driver code
int main() {
    base* bptr;
    derived d;
    bptr = &d;
 
    // Virtual function, binded at runtime (Runtime polymorphism)
    bptr->print();
 
    // Non-virtual function, binded at compile time
    bptr->show();
 
    return 0;
}

Output:

print derived class
show base class

Explanation:

  • bptr->print(): The print() function is virtual, so its behavior is determined at runtime. Since bptr points to a derived object, the print() function of the derived class is called.
  • bptr->show(): The show() function is not virtual, so its behavior is determined at compile time. Since bptr is of type base*, the show() function of the base class is called.

Pure Virtual Function

A pure virtual function in C++ is a virtual function declared in a base class that has no implementation provided. It is declared with the virtual keyword followed by = 0, indicating that the function is pure virtual. Pure virtual functions are meant to be overridden by derived classes, and any class containing a pure virtual function becomes an abstract class, which cannot be instantiated.

#include <iostream>  
using namespace std;  
 
// Abstract base class
class Base  
{  
public:  
    // Pure virtual function
    virtual void show() = 0;  
};  
 
// Derived class
class Derived : public Base  
{  
public:  
    // Implementing the pure virtual function
    void show() 
    {  
        cout << "Derived class is derived from the base class." << endl;  
    }  
};  
 
int main()  
{  
    Base *bptr;  
    //Base b;  // Uncommenting this line will result in a compilation error
    Derived d;  
    bptr = &d;  
    bptr->show(); // Calls the overridden show() function in Derived class
    return 0;  
}  

Output:

Derived class is derived from the base class.

In this example:

  • Base is an abstract base class containing a pure virtual function show().
  • Derived is a derived class that overrides the show() function.
  • Attempting to instantiate an object of the abstract class Base results in a compilation error.
  • Derived objects can be instantiated and can call the show() function, which is provided with an implementation in the derived class.

Difference Between Virtual and Pure Virtual Function

FeatureVirtual FunctionPure Virtual Function
DefinitionA virtual function is a member function in a base class declared with virtual. It is meant to be overridden in derived classes.A pure virtual function has no implementation in the base class. Declared with virtual returnType functionName() = 0;
UsageUsed when a function in the base class should be overridden in derived classes, but the base class may provide a default implementation.Used when the base class does not have a meaningful implementation for a function and expects derived classes to provide their own.
ImplementationMay have a default implementation in the base class. Derived classes can choose to override it.Has no implementation in the base class. Derived classes must provide an implementation, or the base class remains abstract.
Object CreationObjects of the base class can be instantiated, but the overridden function in the derived class will be called if invoked through a base class pointer or reference.Cannot instantiate objects of the base class if it contains pure virtual functions. Derived classes must implement all pure virtual functions to be instantiated.
How's article quality?

Last updated on -

Page Contents