Lesson 16 • Advanced
Advanced OOP in C++
Master virtual tables, abstract classes, multiple inheritance, and compile-time polymorphism with CRTP.
What You'll Learn
- ✓ How vtables enable runtime polymorphism
- ✓ Abstract classes and pure virtual functions
- ✓ Multiple inheritance and the diamond problem
- ✓ CRTP for static polymorphism
Virtual Tables (vtables) — How Polymorphism Works
When you declare a virtual function, the compiler creates a virtual table (vtable) for the class — an array of function pointers. Each object gets a hidden vptr that points to its class's vtable. When you call a virtual function through a base pointer, the CPU looks up the correct function in the vtable at runtime.
This is why virtual function calls are slightly slower than non-virtual ones — there's an extra pointer dereference. But the flexibility of runtime polymorphism is almost always worth the cost.
vtable & Virtual Functions
See polymorphic dispatch and virtual destructors in action
#include <iostream>
using namespace std;
class Animal {
public:
virtual void speak() const {
cout << "Animal speaks" << endl;
}
virtual void move() const {
cout << "Animal moves" << endl;
}
virtual ~Animal() {
cout << "Animal destroyed" << endl;
}
};
class Dog : public Animal {
public:
void speak() const override {
cout << "Dog barks: Woof!" << endl;
}
void move() const override {
cout << "Dog runs on four legs" << end
...Abstract Classes
Build a polymorphic shape hierarchy with pure virtual functions
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
// Pure abstract class (interface)
class Shape {
public:
virtual double area() const = 0; // Pure virtual
virtual double perimeter() const = 0; // Pure virtual
virtual string name() const = 0;
virtual ~Shape() = default;
// Non-virtual: shared behaviour
void describe() const {
cout << name() << ": area=" << area()
<< ", perimeter=" << perimeter() << endl;
}
}
...Multiple Inheritance & the Diamond Problem
C++ allows a class to inherit from multiple bases. The diamond problem occurs when two bases share a common ancestor — should the derived class have one or two copies of the ancestor? Use virtual inheritance to ensure only one copy exists.
Diamond Inheritance
Solve the diamond problem with virtual inheritance
#include <iostream>
using namespace std;
// The Diamond Problem and virtual inheritance
class Device {
protected:
string serialNumber;
public:
Device(string sn) : serialNumber(sn) {
cout << "Device(" << sn << ") constructed" << endl;
}
virtual ~Device() = default;
string getSerial() const { return serialNumber; }
};
// virtual inheritance prevents duplicate Device base
class Printer : virtual public Device {
public:
Printer(string sn) : Device(sn) {
cout
...CRTP Pattern
Use the Curiously Recurring Template Pattern for zero-overhead polymorphism
#include <iostream>
using namespace std;
// CRTP: Curiously Recurring Template Pattern
// Static polymorphism — no virtual function overhead
template <typename Derived>
class Countable {
static int count;
public:
Countable() { ++count; }
Countable(const Countable&) { ++count; }
~Countable() { --count; }
static int getCount() { return count; }
};
template <typename Derived>
int Countable<Derived>::count = 0;
class Enemy : public Countable<Enemy> {
string type;
publ
...Common Mistakes
⚠️ Missing virtual destructor: Deleting a derived object through a base pointer without a virtual destructor causes undefined behaviour.
⚠️ Forgetting override: Without override, a typo in the function signature creates a new function instead of overriding.
⚠️ Slicing: Assigning a derived object to a base variable (not pointer/reference) slices off the derived part.
Pro Tips
💡 Always use override: The override keyword catches signature mismatches at compile time.
💡 Prefer composition: Multiple inheritance adds complexity. Often, composition (has-a) is cleaner than inheritance (is-a).
💡 Use final: Mark classes or methods final to prevent further overriding — the compiler can devirtualize calls for better performance.
📋 Quick Reference
| Concept | Syntax |
|---|---|
| Pure virtual | virtual void f() = 0; |
| Override | void f() override; |
| Final class | class X final : Base {}; |
| Virtual inheritance | class D : virtual public Base |
| Virtual destructor | virtual ~Base() = default; |
Lesson Complete!
You've mastered advanced OOP concepts including vtables, abstract classes, the diamond problem, and CRTP. Next: Templates Deep Dive — variadic templates, SFINAE, and compile-time metaprogramming.
Sign up for free to track which lessons you've completed and get learning reminders.