A base-class function declared virtual, allowing a derived class to override it such that the correct derived version is called through a base-class pointer/reference at runtime (dynamic binding).
class Shape
{
public:
virtual double area() { return 0; } // virtual -- can be overridden
virtual ~Shape() {} // virtual destructor -- required for polymorphic base classes
};
class Circle : public Shape
{
double radius;
public:
Circle(double r) : radius(r) {}
double area() override { return 3.1416 * radius * radius; }
};
Shape* s = new Circle(5);
cout << s->area(); // calls Circle::area(), NOT Shape::area() -- dynamic dispatch
delete s;
Without virtual, s->area() would call Shape::area() regardless of the actual object type ("static binding") — the virtual keyword is what enables runtime polymorphism.
class Animal { public: void speak() { cout << "Some sound\n"; } }; // NOT virtual
class Dog : public Animal { public: void speak() { cout << "Bark!\n"; } };
Animal* a = new Dog();
a->speak(); // prints "Some sound" -- WRONG result if you wanted Dog's version
Without virtual, the compiler binds the call to Animal::speak() at compile time, based purely on the pointer's declared type — this is called static binding.
class Animal { public: virtual void speak() { cout << "Some sound\n"; } }; // now virtual
class Dog : public Animal { public: void speak() override { cout << "Bark!\n"; } };
Animal* a = new Dog();
a->speak(); // prints "Bark!" -- CORRECT -- resolved at runtime based on the actual object
This is dynamic binding: the compiler inserts a lookup through a hidden table (the vtable) at runtime to find the correct function for the object's actual type, not its declared pointer type.
Every class with at least one virtual function gets a hidden vtable (virtual table) — an array of function pointers, one per virtual function. Each object of that class carries a hidden pointer (vptr) to its class's vtable. When you call a->speak(), the program follows a's vptr to the vtable and calls whichever speak() is listed there — which is Dog::speak() if a actually points to a Dog.
override keyword (good practice, not mandatory)class Dog : public Animal
{
public:
void speak() override { cout << "Bark!\n"; } // 'override' -- compiler checks this actually overrides something
// void spek() override { ... } -- COMPILE ERROR: no matching virtual function to override (typo caught!)
};
override doesn't change behavior — it makes the compiler verify you're actually overriding a real virtual function, catching typos like spek() instead of speak() at compile time instead of silently creating an unrelated new function.
this pointer only b) vptr, pointing to the class's vtable c) Static pointer d) Friend pointeroverride keyword:
virtual, calling a derived method through a base pointer uses: