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.

The problem virtual functions solve

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.

The fix

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.

How it works internally (brief, exam-relevant)

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.

The 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.

Important MCQs

  1. A hidden table of function pointers used to implement runtime polymorphism is called the:
  2. Every object of a class with at least one virtual function carries a hidden pointer called the:
  3. The override keyword:
  4. Without virtual, calling a derived method through a base pointer uses:

Self-Test Questions