WikiGalaxy

Personalize

C++ Polymorphism

Definition and Overview:

Polymorphism in C++ is the ability of a function or an object to take multiple forms. It allows objects of different classes to be treated as objects of a common base class. It is one of the core concepts of Object-Oriented Programming (OOP).

Compile-Time Polymorphism:

Also known as static polymorphism, it is achieved through function overloading and operator overloading. The function to be invoked is determined at compile time.

Runtime Polymorphism:

Also known as dynamic polymorphism, it is achieved using inheritance and virtual functions. The function to be invoked is determined at runtime.

Function Overloading:

Function overloading allows multiple functions with the same name but different parameters to exist. The correct function is called based on the arguments passed.

Operator Overloading:

Operator overloading allows you to redefine the way operators work for user-defined types. It makes code intuitive and readable.


#include <iostream>
using namespace std;

class Base {
public:
    virtual void show() {
        cout << "Base class show function" << endl;
    }
    void display() {
        cout << "Base class display function" << endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        cout << "Derived class show function" << endl;
    }
    void display() {
        cout << "Derived class display function" << endl;
    }
};

int main() {
    Base* b;
    Derived d;
    b = &d;

    b->show();      // Runtime polymorphism
    b->display();   // Compile-time binding
    return 0;
}
    

Virtual Functions:

Virtual functions ensure that the correct function is called for an object, regardless of the type of reference (or pointer) used for the function call.

Pure Virtual Functions:

A pure virtual function is declared by assigning 0 in the declaration. Classes containing pure virtual functions are abstract classes.

Console Output:

Derived class show function

Base class display function

Function Overloading Example

Concept of Function Overloading:

Function overloading allows us to have more than one function with the same name in a class that differs only in their parameter list.


#include <iostream>
using namespace std;

class Print {
public:
    void show(int i) {
        cout << "Integer: " << i << endl;
    }
    void show(double d) {
        cout << "Double: " << d << endl;
    }
    void show(string s) {
        cout << "String: " << s << endl;
    }
};

int main() {
    Print p;
    p.show(5);
    p.show(9.5);
    p.show("C++");
    return 0;
}
    

Benefits of Function Overloading:

It improves code readability and usability by allowing the same function name to handle different types of data.

Console Output:

Integer: 5

Double: 9.5

String: C++

Operator Overloading Example

Concept of Operator Overloading:

Operator overloading allows us to define the behavior of operators for user-defined data types. It enhances the intuitive nature of user-defined classes.


#include <iostream>
using namespace std;

class Complex {
private:
    float real, imag;
public:
    Complex(float r = 0, float i = 0) : real(r), imag(i) {}
    
    Complex operator + (Complex const &obj) {
        Complex res;
        res.real = real + obj.real;
        res.imag = imag + obj.imag;
        return res;
    }
    
    void display() {
        cout << real << " + i" << imag << endl;
    }
};

int main() {
    Complex c1(10, 5), c2(2, 4);
    Complex c3 = c1 + c2;
    c3.display();
    return 0;
}
    

Advantages of Operator Overloading:

It increases code clarity and allows user-defined types to be used with standard operators, maintaining consistency in expressions.

Console Output:

12 + i9

Virtual Functions Example

Understanding Virtual Functions:

Virtual functions are member functions in the base class that you expect to override in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.


#include <iostream>
using namespace std;

class Animal {
public:
    virtual void sound() {
        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* a1 = new Dog();
    Animal* a2 = new Cat();
    
    a1->sound();
    a2->sound();
    
    delete a1;
    delete a2;
    return 0;
}
    

Benefits of Virtual Functions:

They facilitate achieving runtime polymorphism, which allows for more flexible and reusable code.

Console Output:

Dog barks

Cat meows

Pure Virtual Functions Example

Concept of Pure Virtual Functions:

A pure virtual function is a function that must be overridden in any derived class. It is declared by assigning 0 in the base class and makes the base class abstract.


#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() = 0; // Pure virtual function
};

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

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

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

Advantages of Pure Virtual Functions:

They enforce the implementation of a function in derived classes, ensuring that specific functionality is provided.

Console Output:

Drawing Circle

Drawing Square

Abstract Class Example

Understanding Abstract Classes:

An abstract class is a class that cannot be instantiated and is designed to be inherited by other classes. It usually contains at least one pure virtual function.


#include <iostream>
using namespace std;

class Vehicle {
public:
    virtual void start() = 0; // Pure virtual function
};

class Car : public Vehicle {
public:
    void start() override {
        cout << "Car started" << endl;
    }
};

class Bike : public Vehicle {
public:
    void start() override {
        cout << "Bike started" << endl;
    }
};

int main() {
    Vehicle* v1 = new Car();
    Vehicle* v2 = new Bike();
    
    v1->start();
    v2->start();
    
    delete v1;
    delete v2;
    return 0;
}
    

Significance of Abstract Classes:

They provide a blueprint for derived classes and ensure that certain methods are implemented in the derived classes.

Console Output:

Car started

Bike started

Dynamic Binding Example

Concept of Dynamic Binding:

Dynamic binding refers to the process where the code to be executed in response to function calls is decided at runtime. It is essential for achieving runtime polymorphism.


#include <iostream>
using namespace std;

class Media {
public:
    virtual void play() {
        cout << "Playing media" << endl;
    }
};

class Video : public Media {
public:
    void play() override {
        cout << "Playing video" << endl;
    }
};

class Audio : public Media {
public:
    void play() override {
        cout << "Playing audio" << endl;
    }
};

int main() {
    Media* m1 = new Video();
    Media* m2 = new Audio();
    
    m1->play();
    m2->play();
    
    delete m1;
    delete m2;
    return 0;
}
    

Advantages of Dynamic Binding:

It allows for more flexible and extensible code, enabling developers to implement changes without affecting existing code.

Console Output:

Playing video

Playing audio

Polymorphism with Interfaces Example

Role of Interfaces in Polymorphism:

While C++ does not have interfaces like Java, abstract classes with only pure virtual functions can serve as interfaces. They allow different classes to implement the same set of functions, ensuring a consistent interface.


#include <iostream>
using namespace std;

class Printable {
public:
    virtual void print() = 0; // Pure virtual function
};

class Document : public Printable {
public:
    void print() override {
        cout << "Printing document" << endl;
    }
};

class Photo : public Printable {
public:
    void print() override {
        cout << "Printing photo" << endl;
    }
};

int main() {
    Printable* p1 = new Document();
    Printable* p2 = new Photo();
    
    p1->print();
    p2->print();
    
    delete p1;
    delete p2;
    return 0;
}
    

Benefits of Using Interfaces:

They promote a design that is easily extendable and maintainable, allowing multiple classes to implement the same functionality.

Console Output:

Printing document

Printing photo

Polymorphism with Templates Example

Templates and Polymorphism:

Templates in C++ provide a way to achieve polymorphism without the overhead of virtual functions. They allow functions and classes to operate with generic types.


#include <iostream>
using namespace std;

template <typename T>
class Calculator {
public:
    T add(T a, T b) {
        return a + b;
    }
    T subtract(T a, T b) {
        return a - b;
    }
};

int main() {
    Calculator<int> intCalc;
    Calculator<double> doubleCalc;
    
    cout << "Int Add: " << intCalc.add(2, 3) << endl;
    cout << "Double Subtract: " << doubleCalc.subtract(5.5, 2.2) << endl;
    
    return 0;
}
    

Advantages of Using Templates:

They enable code reusability and flexibility, allowing the same code to work with different data types without duplication.

Console Output:

Int Add: 5

Double Subtract: 3.3

logo of wikigalaxy

Newsletter

Subscribe to our newsletter for weekly updates and promotions.

Privacy Policy

 • 

Terms of Service

Copyright © WikiGalaxy 2025