C++ में Virtual Function: क्यों होता है, आसान Example के साथ
Virtual के बिना base pointer child object के लिए भी base version call करता है. virtual call को runtime पर actual object से decide करवाता है. Before/after proof.
First, feel the problem (without virtual)
#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;
}
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;
}
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!
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!
virtual ~Animal() { }.Summary table
| Point | Normal function | Virtual function |
|---|---|---|
| Call decided | Compile time (early binding) | Runtime (late binding) |
| Decided by | Pointer/reference type | Actual object type |
| Mechanism | Direct call | vtable lookup |
| Enables | — | Runtime polymorphism |
| Cost | None | Tiny (one pointer lookup) |
पहले problem को महसूस करें (बिना virtual के)
#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;
}
गलत 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;
}
सही! 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!
एक 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!
virtual ~Animal() { }.Summary table
| Point | Normal function | Virtual function |
|---|---|---|
| Call decide | Compile time (early binding) | Runtime (late binding) |
| Decide करता है | Pointer/reference का type | असली object का type |
| Mechanism | Direct call | vtable lookup |
| Enable करता है | — | Runtime polymorphism |
| Cost | कुछ नहीं | बहुत छोटी (एक pointer lookup) |
Frequently Asked Questions
Virtual function आसान शब्दों में क्या है?
Virtual function compiler से कहता है कि कौन-सा version call होगा यह runtime पर असली object देखकर decide हो, compile time पर pointer type देखकर नहीं — इसी से runtime polymorphism मिलती है.
vtable क्या है?
Virtual function addresses की hidden table जो compiler हर class के लिए बनाता है; हर object अपनी class की vtable का pointer रखता है, जिससे runtime पर सही function मिलता है.
Base class का destructor virtual क्यों होना चाहिए?
ताकि base pointer से derived object delete करने पर derived destructor भी चले; वरना सिर्फ base हिस्सा destroy होता है और derived हिस्से के resources leak होते हैं.