Inheritance & Polymorphism
c2-7 ended by naming this chapter directly: what a struct of function pointers, wired up by hand, actually becomes once C++ does it for you. This is that reveal, in full.
Base and Derived Classes
Without virtual — The Problem
A genuine, surprising gotcha: calling area() through a Shape * pointing at a Circle calls Shape's own area(), not Circle's. This is static binding — resolved at compile time, based on the pointer's declared type, not the actual object it points to.
virtual — Making Dispatch Real
Adding virtual changes everything: dispatch now resolves at runtime, based on the actual object's real type. This is exactly c2-7's own hand-built mechanism, made real by the language.
The vtable, Named Directly
Under the hood, a class with virtual functions gets a hidden vtable — a table of function pointers, exactly c2-7's own hand-rolled Circle struct with its own function-pointer member. Every object of such a class carries a hidden pointer to its class's vtable. Calling a virtual function through a base pointer looks up the real function through this table, at runtime — literally the same shape->area(shape) code c2-7 wrote by hand, now generated automatically.
override and Pure Virtual Functions
override (C++11+) is a safety check confirming a derived function genuinely overrides a base virtual — catching typos or signature mismatches as compile errors instead of silently creating an unrelated function.
= 0 marks a pure virtual function — the class becomes abstract, unable to be instantiated directly, requiring every derived class to provide its own implementation.
| Concept | C (c2-7) | C++ |
|---|---|---|
| Dispatch table | hand-written struct of function pointers | vtable — generated automatically |
| Wiring a function pointer correctly | the programmer's own responsibility, unchecked | the compiler builds it, guaranteed correct |
| Forcing an implementation to exist | no mechanism — a NULL entry is UB when called | = 0 (pure virtual) — a compile-time requirement |
virtual, calls the wrong function, and gives no warning by default. C, by contrast, never pretends to have automatic dispatch at all — c2-7's own struct-of-function-pointers approach fails loudly (a NULL call) rather than silently calling the wrong thing.
Coding Challenges
Write a Shape base class with a non-virtual area() returning 0, and a Circle derived class overriding it. Call area() through a Shape* pointing at a Circle and report what actually gets called.
📄 View solutionAdd virtual to Shape::area() from Challenge 1 (and override to Circle::area()), then run the identical Shape* call again. Report how the result changed and why.
📄 View solutionExplain precisely what the vtable is, and why calling a virtual function through a base-class pointer is described as "the exact code c2-7 built by hand, generated automatically" — name the specific piece c2-7 wrote manually that the vtable now replaces.
📄 View solutionChapter 7 Quick Reference
class Derived : public Base { }— inherits members and methods- Without
virtual— static binding, resolved by the pointer's declared type at compile time - With
virtual— dynamic binding, resolved by the actual object's type at runtime - The vtable — a hidden, compiler-generated table of function pointers, exactly
c2-7's own hand-rolled mechanism override— compile-time safety check;= 0— pure virtual, makes a class abstract- Always give a base class with virtual functions a virtual destructor
- Next chapter: references vs. pointers, in depth — when to reach for each