Skip to content
C++

Inheritance — Quick Reference

C++ inheritance cheatsheet — access specifiers, virtual dispatch, override/final, virtual destructor, abstract classes, multiple inheritance, and common pitfalls.

Access Specifiers in Inheritance

cpp
class Base { public: int pub; protected: int prot; private: int priv; };

class D_pub   : public    Base { /* pub→public, prot→protected, priv→inaccessible */ };
class D_prot  : protected Base { /* pub→protected, prot→protected, priv→inaccessible */ };
class D_priv  : private   Base { /* pub→private, prot→private, priv→inaccessible */ };

Virtual Dispatch

cpp
struct Animal {
    virtual std::string speak() const = 0;  // pure virtual
    virtual void        breathe() const { std::println("breathe"); }  // virtual default
    void                live()   const  { std::println("live"); }      // non-virtual
    virtual ~Animal() = default;           // ALWAYS virtual in polymorphic base
};

struct Dog : Animal {
    std::string speak() const override { return "woof"; }
    void        breathe() const override { std::println("pant"); }
};

Animal* a = new Dog{};
a->speak();    // Dog::speak() — virtual dispatch
a->breathe();  // Dog::breathe() — virtual dispatch
a->live();     // Animal::live() — no dispatch (non-virtual)
delete a;      // ~Dog() called — safe because destructor is virtual

override and final

cpp
struct Base {
    virtual void foo(int) = 0;
    virtual void bar() {}
};

struct Mid : Base {
    void foo(int) override {}     // override checks signature
    void bar() final {}           // bar cannot be overridden further
    // void foo(float) override;  // ERROR: no virtual to override
};

struct Leaf final : Mid {         // Leaf cannot be subclassed
    // void bar() override;       // ERROR: bar is final
};

Constructor/Destructor Order

cpp
struct A { A(){puts("A()");} ~A(){puts("~A()");} };
struct B : A { B(){puts("B()");} ~B(){puts("~B()");} };
struct C : B { C(){puts("C()");} ~C(){puts("~C()");} };

C c;
// A()  B()  C()   — construction: base → derived
// ~C() ~B() ~A()  — destruction:  derived → base

Calling Base Class Method

cpp
struct Animal {
    virtual std::string describe() const { return "Animal"; }
};

struct Dog : Animal {
    std::string describe() const override {
        return Animal::describe() + " + Dog";  // explicit base call
    }
};

Abstract Class Rules

cpp
struct Interface {
    virtual void go() = 0;            // pure virtual
    virtual ~Interface() = default;   // virtual dtor
};
// Interface{};  // ERROR: cannot instantiate abstract class
// static_assert(std::is_abstract_v<Interface>);

Multiple Inheritance (Interfaces)

cpp
struct IDrawable   { virtual void draw()   = 0; virtual ~IDrawable() = default; };
struct IClickable  { virtual void click()  = 0; virtual ~IClickable() = default; };
struct IResizable  { virtual void resize() = 0; virtual ~IResizable() = default; };

class Button : public IDrawable, public IClickable, public IResizable {
    void draw()   override { std::println("draw"); }
    void click()  override { std::println("click"); }
    void resize() override { std::println("resize"); }
};

Virtual Inheritance (Diamond Fix)

cpp
struct Animal { std::string name; };
struct Dog   : virtual Animal {};
struct Robot : virtual Animal {};
struct Cyborg : Dog, Robot {};   // one Animal subobject shared

Cyborg c;
c.name = "Fido";  // unambiguous — one shared Animal

Pitfalls

cpp
// ❌ Slicing: derived state lost when assigned to base by value
Dog d;
Animal a = d;  // sliced: only Animal part copied

// ❌ Non-virtual destructor: UB when deleting derived through base ptr
struct Bad { virtual void f(){} };  // forgot virtual ~Bad()
// delete (Bad*)new Dog{};  // UB

// ❌ Calling virtual function in constructor/destructor
struct Unsafe {
    Unsafe() { init(); }       // calls Unsafe::init(), NOT derived override
    virtual void init() {}
};
Edit on GitHub