Virtual Functions and Runtime Polymorphism in C++ (original) (raw)

Last Updated : 19 Jan, 2026

A virtual function is a member function declared in a base class using the virtual keyword and overridden in a derived class. Virtual functions enable runtime polymorphism, where the function call is resolved at runtime based on the actual object type, not the pointer or reference type.

Runtime polymorphism is achieved through late binding, allowing different behaviors for the same function call in an inheritance hierarchy.

classa

Class Hierarchy

Important Notes About Virtual Functions

Example Without Virtual Functions (Static Binding)

C++ `

#include using namespace std;

// Base class class Shape { public: Shape(int l, int w) : length(l), width(w) {}

int get_Area() {
    cout << "This is call to parent class area\n";
    return 1;
}

protected: int length, width; };

// Derived class class Square : public Shape { public: Square(int l, int w) : Shape(l, w) {}

int get_Area() {
    cout << "Square area: " << length * width << endl;
    return length * width;
}

};

// Derived class class Rectangle : public Shape { public: Rectangle(int l, int w) : Shape(l, w) {}

int get_Area() {
    cout << "Rectangle area: " << length * width << endl;
    return length * width;
}

};

int main() { Shape* s;

Square sq(5, 5);
Rectangle rec(4, 5);

s = &sq;
s->get_Area();

s = &rec;
s->get_Area();

return 0;

}

`

Output

This is call to parent class area This is call to parent class area

**Explanation:

Runtime Polymorphism Using Virtual Functions

To achieve runtime polymorphism, the base class function must be declared as virtual.

Example: C++ Program to Calculate the Area of Shapes using Virtual Function

C++ `

#include using namespace std;

// Base class class Shape { public: virtual void calculate() { cout << "Area of your Shape" << endl; }

virtual ~Shape() {
    cout << "Shape Destructor Call\n";
}

};

// Derived class class Rectangle : public Shape { public: int width, height;

void calculate() {
    cout << "Enter Width of Rectangle: ";
    cin >> width;
    cout << "Enter Height of Rectangle: ";
    cin >> height;
    cout << "Area of Rectangle: " << width * height << endl;
}

~Rectangle() {
    cout << "Rectangle Destructor Call\n";
}

};

// Derived class class Square : public Shape { public: int side;

void calculate() {
    cout << "Enter side of Square: ";
    cin >> side;
    cout << "Area of Square: " << side * side << endl;
}

~Square() {
    cout << "Square Destructor Call\n";
}

};

int main() { Shape* s;

Rectangle r;
s = &r;
s->calculate();

Square sq;
s = &sq;
s->calculate();

return 0;

}

`

**Output

Enter Width of Rectangle: 5
Enter Height of Rectangle: 10
Area of Rectangle: 50
Enter side of Square: 8
Area of Square: 64

Square Destructor Call
Shape Destructor Call
Rectangle Destructor Call
Shape Destructor Call

Explanation

Why Virtual Destructors Are Important

Real-Life Example: Employee Management System

Consider employee management system where a base class Employee defines virtual functions such as raiseSalary() and promote(), which are overridden by derived classes like Manager or Engineer. This allows operations to be performed on a list of employees while the correct behavior is selected at runtime without knowing the specific employee type.

CPP `

class Employee { public: virtual void raiseSalary() { // common raise logic }

virtual void promote() {
    // common promotion logic
}

};

class Manager : public Employee { public: void raiseSalary() { // manager-specific salary logic }

void promote() {
    // manager-specific promotion logic
}

};

void globalRaiseSalary(Employee* emp[], int n) { for (int i = 0; i < n; i++) { emp[i]->raiseSalary(); // Polymorphic call } }

`

**Explanation:

Internal Working of Runtime Resolution

The compiler uses two internal mechanisms:

array

Runtime Process

1. Constructor initializes the vptr.

2. On a virtual call, the compiler:

Related Article:

vtable vs vptr