Free tutorials in Hindi & English Daily computer, mobile and IT guides Beginner friendly learning
Blog · C++ · 04 Jul 2026 · Hindi + English

Virtual Function in C++: Why It Exists, With Simple Example

Without virtual, a base pointer calls the base version even for a child object. virtual makes the call decided at runtime by the actual object. Before/after proof.

First, feel the problem (without virtual)

Virtual functions solve one specific problem. To understand them, you must first see the problem. Here it is:
#include <iostream>
using namespace std;

class Animal {
public:
    void sound() { cout << "Some generic sound\n"; }   // NOT virtual
};

class Dog : public Animal {
public:
    void sound() { cout << "Bark!\n"; }
};

int main() {
    Animal *a = new Dog();     // base pointer, but Dog object!
    a->sound();                 // which version runs?
    delete a;
    return 0;
}
Some generic sound

Wrong answer came out! The object is a Dog, but "Some generic sound" printed. Why? Without virtual, the compiler decides the call by looking at the pointer's type (Animal*) at compile time. It never looks at the actual object. This is called early binding.

Now add one word — virtual

class Animal {
public:
    virtual void sound() { cout << "Some generic sound\n"; }  // virtual!
};

class Dog : public Animal {
public:
    void sound() override { cout << "Bark!\n"; }
};

int main() {
    Animal *a = new Dog();
    a->sound();                 // now?
    delete a;
    return 0;
}
Bark!

Correct! The word virtual tells the compiler: "don't decide now — wait until the program runs and look at the actual object". This is late binding / runtime polymorphism. Internally, the compiler builds a hidden table of function addresses (the vtable) and each object carries a pointer to its class's table — that is how the right version is found at runtime.

Why this matters in real code

void morningRoutine(Animal *a) {     // works for ANY animal -
    a->sound();                       // even ones written NEXT YEAR
}

Dog d; Cat c; Cow w;
morningRoutine(&d);    // Bark!
morningRoutine(&c);    // Meow!
morningRoutine(&w);    // Moo!
Bark! Meow! Moo!

One function handles every present and future animal type without modification. Every plugin system, every GUI framework, every game engine runs on exactly this mechanism.

The virtual destructor rule (senior-level question)

Animal *a = new Dog();
delete a;      // if ~Animal() is NOT virtual:
               // only Animal's destructor runs, Dog's part leaks!
Rule: if a class has any virtual function, its destructor should also be virtual. Otherwise deleting a child object through a base pointer destroys only the base part — Dog's resources leak. One line fixes it: virtual ~Animal() { }.

Summary table

PointNormal functionVirtual function
Call decidedCompile time (early binding)Runtime (late binding)
Decided byPointer/reference typeActual object type
MechanismDirect callvtable lookup
EnablesRuntime polymorphism
CostNoneTiny (one pointer lookup)

पहले problem को महसूस करें (बिना virtual के)

Virtual functions एक specific problem solve करते हैं. समझने के लिए पहले problem को देखना ज़रूरी है. यह रही:
#include <iostream>
using namespace std;

class Animal {
public:
    void sound() { cout << "Some generic sound\n"; }   // virtual NAHI
};

class Dog : public Animal {
public:
    void sound() { cout << "Bark!\n"; }
};

int main() {
    Animal *a = new Dog();     // base pointer, लेकिन Dog object!
    a->sound();                 // कौन-सा version चलेगा?
    delete a;
    return 0;
}
Some generic sound

गलत answer निकला! Object Dog है, लेकिन "Some generic sound" print हुआ. क्यों? Virtual के बिना compiler call को compile time पर pointer के type (Animal*) से decide करता है. असली object को देखता ही नहीं. इसे early binding कहते हैं.

अब सिर्फ एक शब्द जोड़ें — virtual

class Animal {
public:
    virtual void sound() { cout << "Some generic sound\n"; }  // virtual!
};

class Dog : public Animal {
public:
    void sound() override { cout << "Bark!\n"; }
};

int main() {
    Animal *a = new Dog();
    a->sound();                 // अब?
    delete a;
    return 0;
}
Bark!

सही! virtual शब्द compiler से कहता है: "अभी decide मत करो — program चलने तक रुको और असली object देखो". यही late binding / runtime polymorphism है. अंदर से compiler function addresses की एक hidden table (vtable) बनाता है और हर object अपनी class की table का pointer साथ रखता है — runtime पर सही version ऐसे मिलता है.

Real code में यह क्यों matter करता है

void morningRoutine(Animal *a) {     // HAR animal के लिए चलता है -
    a->sound();                       // अगले साल लिखे जाने वालों के लिए भी
}

Dog d; Cat c; Cow w;
morningRoutine(&d);    // Bark!
morningRoutine(&c);    // Meow!
morningRoutine(&w);    // Moo!
Bark! Meow! Moo!

एक function हर मौजूदा और आने वाले animal type को बिना बदलाव के handle करता है. हर plugin system, हर GUI framework, हर game engine इसी mechanism पर चलता है.

Virtual destructor rule (senior-level question)

Animal *a = new Dog();
delete a;      // अगर ~Animal() virtual NAHI है:
               // सिर्फ Animal का destructor चलेगा, Dog का हिस्सा leak!
Rule: अगर class में कोई भी virtual function है, तो destructor भी virtual होना चाहिए. वरना base pointer से child object delete करने पर सिर्फ base हिस्सा destroy होता है — Dog के resources leak हो जाते हैं. एक line से fix: virtual ~Animal() { }.

Summary table

PointNormal functionVirtual function
Call decideCompile time (early binding)Runtime (late binding)
Decide करता हैPointer/reference का typeअसली object का type
MechanismDirect callvtable lookup
Enable करता हैRuntime polymorphism
Costकुछ नहींबहुत छोटी (एक pointer lookup)

Frequently Asked Questions

What is a virtual function in simple words?

A virtual function tells the compiler to decide which version to call at runtime based on the actual object, not at compile time based on the pointer type — enabling runtime polymorphism.

What is a vtable?

A hidden table of virtual function addresses that the compiler creates per class; each object carries a pointer to its class vtable, which is how the correct function is found at runtime.

Why should a base class destructor be virtual?

So that deleting a derived object through a base pointer runs the derived destructor too; otherwise only the base part is destroyed and the derived part leaks resources.