Tutorials Logic, IN info@tutorialslogic.com

C++ Inheritance, Substitutability, and Object Lifetime

Substitution in C++

Public inheritance states an is-a relationship: every derived object must honor the observable promises of the base. Protected or private inheritance models implementation reuse and is usually clearer as composition. Keep hierarchies shallow and give each virtual operation one stable meaning.

A Small Polymorphic Base

Pass the base by reference or pointer to preserve dynamic type. Passing by value slices away the derived portion.

Dispatch through a virtual function

Dispatch through a virtual function
#include <iostream>
#include <memory>

struct Shape {
    virtual ~Shape() = default;
    virtual double area() const = 0;
};
struct Square final : Shape {
    explicit Square(double side) : side{side} {}
    double area() const override { return side * side; }
    double side;
};

int main() {
    std::unique_ptr<Shape> shape = std::make_unique<Square>(4.0);
    std::cout << shape->area() << '\n';
}
Output
16

Multiple and Virtual Inheritance

Multiple inheritance works well for small independent interfaces. Shared base state can create a diamond; virtual inheritance provides one shared base subobject but increases construction and design complexity.

  • Mark overrides with override.
  • Avoid calling virtual behavior from constructors and destructors.
  • Prefer composition when substitutability is weak.

Construction Order

Base subobjects initialize before members and derived construction; destruction occurs in reverse. Initialize the base and members in initializer lists, understanding that member declaration order, not list order, controls initialization. A derived constructor cannot repair an invalid base that was constructed incorrectly.

Do not expose base data as protected merely for convenience. Protected behavior or composed collaborators create a narrower dependency. Mark leaf classes or operations final when extension would violate an invariant or when the design intentionally closes the hierarchy.

Protect the Polymorphic Lifetime

If a base type is intended for polymorphic use, deleting a derived object through a base pointer must invoke the complete destructor chain. Give the base a virtual destructor, use override on derived virtual methods, and prefer smart pointers for ownership.

Inheritance should represent substitutability, not merely shared fields. Favor composition when the derived type must disable, reinterpret, or reject behavior promised by the base.

Virtual Destruction Through a Base Pointer

Virtual Destruction Through a Base Pointer
#include <iostream>
#include <memory>

struct Base { virtual ~Base() { std::cout << "base\n"; } };
struct Derived : Base { ~Derived() override { std::cout << "derived\n"; } };

int main() {
    std::unique_ptr<Base> item = std::make_unique<Derived>();
}
Output
derived
base

The virtual base destructor preserves complete cleanup when ownership is expressed through the base type.

Before you move on

Hierarchy Review

5 checks
  • The derived type satisfies the base contract.
  • The base destructor policy is intentional.
  • Polymorphic objects are passed without slicing.
  • Multiple inheritance combines interfaces, not unrelated state.
  • Composition was considered.

Inheritance Failure Boundary

  • Deleting through a non-virtual base

    A polymorphic base class needs a virtual destructor when objects may be deleted through a base pointer. Otherwise derived cleanup is not guaranteed.

Try this next

Inheritance Safety Practice

0 of 2 completed

  1. Create a polymorphic base and resource-owning derived class, delete the object through a base pointer, and confirm both destructors run. Make the base destructor virtual before treating the result as correct.
  2. Add override to a derived method whose parameter initially differs from the base, compile, and use the diagnostic to repair the contract. override turns a silent new method into a compile-time failure.

Inheritance Questions

Deleting a derived object through a base pointer must run both destructors. Without a virtual destructor, that deletion has undefined behavior.

It prevents a diamond-shaped hierarchy from containing two separate copies of the same base subobject.

Use composition when one object merely uses or owns another. Inheritance should represent a genuine substitutable “is-a” relationship.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.