Virtual Function in C++

Last Updated : 11 Jun, 2026

A virtual function is a member function declared with the virtual keyword in a base class and overridden in a derived class. It allows function calls through base class pointers or references to invoke the implementation corresponding to the actual object type at runtime.

  • Forms the foundation of runtime polymorphism in C++
  • Allows derived classes to customize inherited behavior
  • Enables dynamic function dispatch through base class pointers and references
C++
#include <iostream>
using namespace std;

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

    // Virtual destructor
    virtual ~Shape()
    {
        cout << "Shape Destructor called\n";
    }
};

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

    void calculate() override
    {
        width = 5;
        height = 10;

        area = height * width;
        cout << "Area of Rectangle: " << area << "\n";
    }

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

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

    void calculate() override
    {
        side = 7;
        area = side * side;
        cout << "Area of Square: " << area << "\n";
    }

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

int main()
{

    Shape *S;

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

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

    return 0;
}

Output
Area of Rectangle: 50
Area of Square: 49
Square Destructor called
Shape Destructor called
Rectangle Destructor called
Shape Destructor called

Explanation

  • calculate() is declared virtual in the Shape class.
  • Both Rectangle and Square provide their own implementation.
  • The function call is resolved at runtime based on the actual object type.
  • This behavior is known as runtime polymorphism.

Note: It is a recommended way to use override identifier to avoid mistakes while redefine virtual function inside the derived class.

Pure Virtual Function

A pure virtual function is a virtual function declared with = 0 in a base class. It is used to enforce that derived classes provide their own implementation.

  • A class containing a pure virtual function becomes an abstract class and cannot be instantiated.
  • Derived classes must override the pure virtual function to provide an implementation.
  • A destructor can also be declared as pure virtual (= 0); it makes the class abstract but must still be defined outside the class to ensure proper object cleanup.
C++
#include <iostream>
using namespace std;

class Base
{
  public:
  
    // Pure virtual function
    virtual void display() = 0;

    // Pure virtual destructor
    virtual ~Base() = 0;
};

// Definition of pure virtual destructor
Base::~Base()
{
    cout << "Base destructor called" << endl;
}

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

    ~Derived()
    {
        cout << "Derived destructor called" << endl;
    }
};

int main()
{
    Base *basePtr;
    Derived derivedObj;
    basePtr = &derivedObj;
    basePtr->display();
    return 0;
}

Output
Derived class display

Explanation

  • display() is a pure virtual function, making Base an abstract class.
  • Derived overrides the display() function.
  • The pure virtual destructor is defined separately and ensures proper cleanup.
  • Calling display() through a base class pointer invokes the derived class implementation.

Early Binding and Late Binding

Binding is the process of associating a function call with the function definition that will be executed. In C++, binding can occur at either compile time or runtime.

  • Early Binding (Static Binding): The function call is resolved during compilation. Non-virtual functions use early binding, making function calls faster.
  • Late Binding (Dynamic Binding): The function call is resolved at runtime based on the actual object type. Virtual functions use late binding to enable runtime polymorphism.
C++
#include <iostream>
using namespace std;

class base
{
  public:
    virtual void print()
    {
        cout << "print base "
                "class\n";
    }

    void show()
    {
        cout << "show base class\n";
    }
};

class derived : public base
{
  public:
    void print()
    {
        cout << "print derived class\n";
    }

    void show()
    {
        cout << "show derived class\n";
    }
};

int main()
{
    base *bptr;
    derived d;
    bptr = &d;

    // Virtual function,binded at runtime
    bptr->print();

    // Non-virtual function,binded at compile time
    bptr->show();
    return 0;
}

Output
print derived class
show base class

Explanation

  • print() is a virtual function, so the call is resolved at runtime and executes derived::print().
  • show() is a non-virtual function, so the call is resolved at compile time and executes base::show().
  • This demonstrates the difference between late binding and early binding.

Runtime Resolution Using vtable and vptr

Virtual functions achieve runtime polymorphism through two compiler-generated mechanisms: vtable and vptr.

actual_object
  • vtable (Virtual Table): A table maintained for each class that stores the addresses of its virtual functions.
  • vptr (Virtual Pointer): A hidden pointer stored in each object that points to the corresponding class's vtable.
  • In the diagram, each object contains its own vptr, which points to the appropriate vtable.
  • When a virtual function is called through a base class pointer or reference, the compiler follows the object's vptr to locate the correct function address in the vtable.
  • This ensures that the function belonging to the actual object type (such as Manager or Engineer) is executed at runtime.

Rules for Virtual Functions

Virtual functions follow these important rules:

  • Virtual functions are defined in the base class and can be overridden in derived classes (not mandatory; base version is used if not overridden).
  • They must have the same prototype in base and derived classes.
  • They are used through a base class pointer or reference to achieve runtime polymorphism.
  • A class may have a virtual destructor in case of dynamic memory allocation, but never a virtual constructor.
  • Virtual functions cannot be static, but they can be friend functions of another class.

Limitations of Virtual Functions

While virtual functions enable runtime polymorphism, they also have some drawbacks:

  • Slight Performance Overhead: Virtual function calls are resolved at runtime, making them slightly slower than normal function calls.
  • Additional Memory Usage: Classes with virtual functions require a hidden vptr for runtime dispatch.
  • Harder to Debug: In complex programs, it can be more difficult to determine which function implementation is actually being executed.
Comment