Compile-Time vs. Runtime Polymorphism in CPP: An Easy Guide.

Welcome to the world of C++ polymorphism! Today, we delve into the intriguing concepts of Compile-Time and Runtime Polymorphism. Polymorphism allows objects to take on multiple forms, and in C++, we have two types: Compile-Time and Runtime. In this article, we’ll explore the need for polymorphism, how it works, and how it benefits our programs. With Compile-Time Polymorphism, we can achieve method overloading using function signatures, while with Runtime Polymorphism, we can leverage virtual functions and dynamic binding. Understanding these polymorphic techniques will empower you to write more flexible and robust C++ code. Let’s dive in!

What is Polymorphism in C++?

Polymorphism in C++ is like giving different meanings to the same word based on the context. In programming, it means the ability of different classes to be treated as instances of a common base class. Imagine you have different types of shapes like circles, squares, and triangles, but you want to work with all of them using a common approach.

Polymorphism lets you do just that. You can create a common interface, like a “draw” function, in a base class. Then, each specific shape class can provide its own version of the “draw” function, tailored to its shape.

For example, when you call the “draw” function on a circle, it will draw a circle. But if you call the same function on a square, it will draw a square. The magic happens because of virtual functions and pointers or references to the base class. This way, you can work with different objects in a unified way, even if they have different behaviors.

In everyday terms, think of a TV remote. The buttons do different things depending on whether you’re controlling a TV, a DVD player, or a streaming device. You’re using the same remote interface to control different devices. Similarly, polymorphism lets you interact with various objects through a common interface, letting them respond based on their unique nature.

Compile-time Polymorphism vs Runtime Polymorphism

There are two types of polymorphism in C++: compile-time polymorphism and runtime polymorphism.

Compile-Time vs. Runtime Polymorphism in CPP: An Easy Guide.
Polymorphism

Compile-time Polymorphism

Compile-time polymorphism in C++ is a concept that allows you to achieve different behaviors for the same function name at compile time. It’s also known as method overloading and operator overloading. This happens because the compiler determines which function to call based on the number and types of arguments passed to it. This way, you can reuse function names and make your code more readable and concise.

Method Overloading:

Method overloading occurs when multiple functions with the same name exist in a class, but they differ in terms of the type or number of parameters they accept. The compiler decides which function to call based on the arguments you provide.

C++
#include 
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 main() {
    Calculator calc;
    cout << calc.add(5, 10) << endl;       // Calls int add(int a, int b)
    cout << calc.add(3.5, 7.2) << endl;    // Calls double add(double a, double b)
    return 0;
}

Output:

C++
15
10.7

Operator Overloading:

Operator overloading allows you to define new behaviors for the standard operators like +, -, *, etc. You can create custom implementations for these operators within a class.

C++
#include 
using namespace std;

class Complex {
private:
    double real;
    double imag;

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

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

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

int main() {
    Complex num1(3.0, 4.0);
    Complex num2(1.5, 2.5);

    Complex sum = num1 + num2;   // Calls the overloaded + operator
    sum.display();               // Outputs: 4.5 + 6.5i

    return 0;
}

Output:

C++
4.5 + 6.5i

Runtime Polymorphism

Runtime polymorphism in C++ is a powerful concept that allows different classes to be treated as instances of a common base class. This enables more flexible and dynamic behavior in your code. This concept is closely related to inheritance and is achieved through the use of virtual functions.

In simple terms, runtime polymorphism allows you to call methods of a derived class through a pointer or reference of the base class, and the appropriate method of the derived class is executed based on the actual object pointed to or referred to, rather than the type of the pointer or reference itself.

Here are the key points to understand about runtime polymorphism:

  • Base Class and Derived Class: In this approach, you have a base class and one or more derived classes. The base class has virtual functions, and these functions are overridden by the derived classes to provide specific implementations.
  • Virtual Function: A virtual function is a member function in the base class that is marked with the virtual keyword. This indicates that the function can be overridden by derived classes.
  • Dynamic Binding: The decision about which function to call is made during runtime, based on the actual type of the object being referred to, rather than the type of the reference or pointer.

Here’s a simple example to illustrate runtime polymorphism:

C++displayArea(); // Output: Area of Circle s2->displayArea(); // Output: Area of Rectangledelete s1; delete s2;return 0; }” style=”color:#D4D4D4;display:none” aria-label=”Copy” class=”code-block-pro-copy-button”>
#include 
using namespace std;

class Shape {
public:
    virtual void displayArea() {
        cout << "Area of Shape" << endl;
    }
};

class Circle : public Shape {
public:
    void displayArea() override {
        cout << "Area of Circle" << endl;
    }
};

class Rectangle : public Shape {
public:
    void displayArea() override {
        cout << "Area of Rectangle" << endl;
    }
};

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

    s1->displayArea();  // Output: Area of Circle
    s2->displayArea();  // Output: Area of Rectangle

    delete s1;
    delete s2;

    return 0;
}

Output:

C++
Area of Circle
Area of Rectangle

Explanation:

  • Base Class and Derived Classes: The code features a base class named “Shape” and two derived classes, “Circle” and “Rectangle,” all linked by inheritance.
  • Virtual Function: The base class has a virtual function called “displayArea()” that is overridden in the derived classes with specific implementations.
  • Polymorphic Behavior: Using base class pointers, instances of “Circle” and “Rectangle” are created in the “main()” function. When calling “displayArea()” through these pointers, the correct overridden method is executed based on the actual object’s type.
  • Common Interface: This approach lets you treat objects of different types uniformly through a shared interface, even though they have diverse implementations.
  • Flexibility and Simplification: Runtime polymorphism enhances code flexibility by enabling dynamic method calls and streamlines handling various objects with a unified approach, making code management easier.

Understand by Detailed Diagram

Compile-time Polymorphism vs Runtime Polymorphism in C++

Compile-time Polymorphism

  • Also known as Static Polymorphism.
  • Resolved at compile time.
  • Achieved through function overloading and operator overloading.
  • Example: void fun(int i) { } and void fun(double d) { }.

Runtime Polymorphism

  • Also known as Dynamic Polymorphism.
  • Resolved at runtime.
  • Achieved through virtual functions and pointers.
  • Example: class Base { public: virtual void show() { } }; class Derived : public Base { public: void show() { } };

Differences between Compile-time Polymorphism and Runtime Polymorphism

AspectCompile-time PolymorphismRuntime Polymorphism
Also Known AsStatic Polymorphism, Method OverloadingDynamic Polymorphism, Method Overriding
Implementation DecisionMade by the compiler at compile timeDetermined at runtime
Method SelectionBased on the number and type of argumentsBased on the actual object type
Function OverloadingMultiple functions with the same nameThe derived class overrides the base class method
MechanismFunction overloading, Operator overloadingVirtual functions and inheritance
ExampleMultiple constructor overloads in a classOverriding a base class method in a subclass
Performance OverheadNone, resolved at compile timeSlightly slower due to method resolution
FlexibilityLimited, as decisions are fixed at compile timeHigh, adaptable to dynamic scenarios
Method BindingEarly binding, also known as static bindingLate binding, also known as dynamic binding
SyntaxFunctions/methods with the same name but different parametersFunctions/methods with the same name and parameters, but different implementations
Use CasesMethod overloading, operator overloadingMethod overriding, polymorphic behavior
Differences between Compile-time Polymorphism and Runtime Polymorphism

Real-life Examples

Let’s look at some examples to understand these concepts better.

Compile-time Polymorphism Example

C++
#include
using namespace std;

class Party {
public:
    void inviteFriends(string name) {
        cout << "Calling " << name << endl;
    }

    void inviteFriends(string name, string method) {
        cout << "Inviting " << name << " by " << method << endl;
    }
};

int main() {
    Party p;
    p.inviteFriends("John");
    p.inviteFriends("Sarah", "email");
    return 0;
}

Output:

C++
Calling John
Inviting Sarah by email

Explanation

  • The code defines a class called “Party” that has two overloaded functions: “inviteFriends” with one parameter and “inviteFriends” with two parameters.
  • The first “inviteFriends” function takes a string parameter representing the name of a friend and outputs a message saying that the person is being called.
  • The second “inviteFriends” function takes two string parameters, the name of a friend and the method of invitation, and outputs a message saying that the person is being invited using the specified method.
  • In the “main” function, an object of the “Party” class is created.
  • The “inviteFriends” functions are called with different arguments to demonstrate the different ways of inviting friends, and appropriate messages are printed based on the provided arguments.

Runtime Polymorphism Example

C++openGift();g = &t; g->openGift();return 0; }” style=”color:#D4D4D4;display:none” aria-label=”Copy” class=”code-block-pro-copy-button”>
#include
using namespace std;

class Gift {
public:
    virtual void openGift() {
        cout << "It's a gift!" << endl;
    }
};

class Book : public Gift {
public:
    void openGift() override {
        cout << "It's a book!" << endl;
    }
};

class Toy : public Gift {
public:
    void openGift() override {
        cout << "It's a toy!" << endl;
    }
};

int main() {
    Gift* g;
    Book b;
    Toy t;

    g = &b;
    g->openGift();

    g = &t;
    g->openGift();

    return 0;
}

Output:

C++
It's a book!
It's a toy!

Explanation:

  • The code uses polymorphism with virtual functions to demonstrate different behaviors based on the object type.
  • The Gift class has a virtual function openGift() that can be overridden by derived classes.
  • The Book and Toy classes inherit from Gift and provide their own implementations of openGift().
  • The main() function creates objects of Book and Toy, assigns them to a Gift* pointer, and calls openGift().
  • Polymorphism allows the appropriate version of openGift() to be executed based on the actual object type.
  • The output shows “It’s a book!” and “It’s a toy!” to demonstrate the dynamic behavior of polymorphism.

Pros and Cons of Compile-time and Runtime Polymorphism

Compile-time PolymorphismRuntime Polymorphism
Binding TimeEarly Binding (Static Binding)Late Binding (Dynamic Binding)
Decided atCompile TimeRuntime
Function OverloadingAchieved through function overloadingNot applicable
Function OverridingNot applicableAchieved through virtual functions
FlexibilityLimited flexibility in changing behaviorHigh flexibility in changing behavior
EfficiencyMore efficientSlightly less efficient
ExampleFunction OverloadingFunction Overriding using virtual functions
Pros and Cons of Compile-time and Runtime Polymorphism

Key Takeaways

  • Polymorphism’s Unified Interface: Polymorphism in C++ enables a single interface to handle diverse actions, enhancing code flexibility.
  • Compile-Time Polymorphism: Function overloading and operator overloading are examples of compile-time polymorphism, resolved during compilation.
  • Runtime Polymorphism: Function overriding and virtual functions exemplify runtime polymorphism, determined during program execution.
  • Important Distinction: Understanding the contrast between compile-time and runtime polymorphism is essential for effective C++ programming.
  • Practice and Proficiency: With practice, mastering polymorphism in C++ will empower you to write adaptable and efficient code.

FAQs

1. What is Compile-time Polymorphism in C++?

Compile-time polymorphism, also known as static or early binding, refers to the situation where the function to be executed is determined at compile time. It is achieved through function overloading and operator overloading.

2. What is Runtime Polymorphism in C++?

Runtime polymorphism, also known as dynamic or late binding, occurs when the function to be executed is not known at compile time but is determined at runtime. It is achieved through function overriding and virtual functions.

3. How does Compile-time Polymorphism work?

Compile-time polymorphism uses function overloading to define multiple functions with the same name but different parameters. The appropriate function is selected based on the number or types of arguments passed during compilation.

4. How does Runtime Polymorphism work?

Runtime polymorphism uses function overriding and virtual functions. When a function is declared as virtual in the base class, it allows derived classes to provide their implementation. The actual function called is determined based on the object’s type during runtime.

5. What are the advantages of Compile-time and Runtime Polymorphism?

Compile-time polymorphism offers better performance and efficiency as the function is known at compile time, leading to optimized code execution. On the other hand, runtime polymorphism provides greater flexibility, allowing dynamic changes in behavior at runtime, making the code more adaptable and maintainable.

Deepak Vishwakarma

Founder

RELATED Articles

Leave a Comment

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