🧬Go deeper — read the bookConstructor inheritance, init order & the Rule of 5— runnable code & full walkthrough →

oops · high

Constructor inheritance & initialization order

How a derived class passes arguments to its base constructor (the member initializer list), the fixed initialization order (base subobjects, then members in declaration order, then the body — destruction reversed), the declaration-order gotcha, inheriting constructors with `using Base::Base` (and the trap that added members are left default-initialized), and how the Rule of 5 interacts with inheritance: keep the resource owner in the base with all five special members, while derived classes stay Rule of 0.

🔑 Key line

Forward base args in the member init list; init order is base -> members (declaration order) -> body; `using Base::Base` inherits constructors only; put the Rule of 5 in the base, keep derived Rule of 0.

The code

struct Animal {
std::string name;
Animal(std::string n) : name(std::move(n)) {} // base ctor
};
struct Dog : Animal {
int legs; // declared 1st
std::string sound; // declared 2nd
Dog(std::string n, int l, std::string s)
: Animal(std::move(n)), // 1) forward args to the base
legs(l), // 2) members, in DECLARATION order
sound(std::move(s)) // legs before sound, always
{
std::cout << "Dog body\n";
} // 3) derived body runs last
};
struct Puppy : Dog {
using Dog::Dog; // inherit every Dog ctor
};
struct Reorder { // classic -Wreorder trap
int a; // declared 1st -> built 1st
int b; // declared 2nd
Reorder(int x) : b(x), a(b) {} // a runs FIRST and reads b!
};

What this lesson walks through

  1. 01You must pass base args in the init list
  2. 02Initialization order is fixed: base → members → body
  3. 03The trap: members init in DECLARATION order, not init-list order
  4. 04Inheriting constructors: `using Base::Base`
  5. 05Inherited-ctor trap: the derived's own members are default-initialized
  6. 06Rule of 5 in a hierarchy: let the base own the resource

A base class is constructed before the derived object exists, so you forward its arguments in the derived constructor's MEMBER INITIALIZER LIST — `Dog(...) : Animal(std::move(n))`. You cannot 'call' the base constructor in the body; by the time the body runs, the base is already built. If you don't name the base, the compiler tries its default constructor — a hard error when the base has none.

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of Constructor inheritance & initialization order and 100+ animated C++ interview lessons.

← Previous
Upcasting, Downcasting, dynamic_cast & RTTI
Next →
Rule of 0 / 3 / 5