Concepts / Class Derivation and Inheritance

Class Derivation and Inheritance

A derived object is usually manipulated through its abstract base class, and it may be deleted through a pointer to that base class.

  • Programming

Why a Base Pointer Can Hide a Derived Object

A derived object is usually manipulated through the interface provided by its abstract base class, and it may be deleted through a pointer to that base class. This is a normal, useful pattern: the rest of the program can work with any shape, vehicle, or account without caring which concrete class it actually is. The catch appears at the moment of cleanup. The pointer only knows the base type, so the question becomes which destructor runs when the object is destroyed.

This article follows one scenario from start to finish: a base class Shape, a derived class Circle, and a delete performed through a Shape pointer. The goal is to understand what the program does at that moment, why it does it, and what goes wrong when the wrong destructor is chosen.

Testing the Assumption About the Base Destructor

A common first assumption goes like this: if a program holds a pointer to a base class and deletes the object it points to, the base class destructor is the only one that matters, because the base pointer is the only thing the program knows about. Under this belief, any cleanup belonging to the derived part of the object is simply assumed to take care of itself.

Before reading further, test that belief. Suppose Shape declares a virtual destructor and Circle is derived from it. A program creates a Circle, stores its address in a Shape pointer, and then deletes it through that pointer. Decide which destructor messages would be printed and in what order.

What do you think happens?

A Circle is created, its address is stored in a Shape pointer, and delete is applied to that pointer. Which destructor messages print, and in what order?

  • Only the Shape destructor prints

  • Only the Circle destructor prints

  • The Circle destructor prints first, then the Shape destructor

  • The Shape destructor prints first, then the Circle destructor

Reveal answer
Answer:

The Circle destructor prints first, then the Shape destructor.

Delete through the Shape pointer reaches the Circle destructor because the base destructor is virtual. The Circle destructor then invokes the Shape destructor, so the derived cleanup happens first and the base cleanup follows.

Tracing a Deletion Through a Shape Pointer

The source explains the reasoning in two steps. First, an object of a derived class is usually manipulated through the interface provided by its abstract base class, and it may be deleted through a pointer to a base class. Second, the virtual function call mechanism ensures that the proper destructor is called in that situation. The pointer's declared type is Shape, but the mechanism routes the deletion to the destructor belonging to the object that actually exists, which is a Circle.

Programcalls deleteShape pointerstatic type ShapeCircle destructorselected at runtimeShape destructorinvoked by Circledelete ptrvirtual call selects Circle destructorimplicitly invokes base destructor
What happens, step by step, when delete is applied to a Shape pointer that actually refers to a Circle. The virtual call mechanism selects the Circle destructor, which then invokes the Shape destructor.

Read the diagram from top to bottom. The program issues the delete. The pointer's type is Shape, but the virtual call mechanism does not stop at the base destructor; it replaces the static choice with the destructor of the real object, which is Circle's. The Circle destructor then does its own cleanup and, as part of finishing, invokes the Shape destructor.

Following the Destructor Chain in Code

The following program puts the scenario into code. Each destructor prints a message so the order of destruction is visible. The base destructor is declared virtual, which is the key detail. The program is an original illustration built from the scenario described in the source.

cpp
Output
Circle destructor
Shape destructor
Notes on the code
  • virtual ~Shape() makes the base destructor virtual
  • new Circle() creates a derived object but stores it in a Shape pointer
  • delete s goes through the base pointer

The output matches the prediction. Even though delete is applied to a Shape pointer, the Circle destructor runs. The virtual call mechanism is what routes the deletion to the proper destructor, and the Shape destructor runs afterward because the Circle destructor invokes it.

Destruction Order Step by Step

The proper destructor does its own part of the cleanup and also implicitly invokes the destructors of its bases and of its members. This is why a single deletion through a base pointer can clean up an entire chain of classes, provided the virtual mechanism selects the right starting destructor. Teardown therefore begins at the most derived destructor and reaches the base layer through the chain.

delete throughShape pointerstarts teardownCircle destructorbodyruns firstShape destructor bodyruns after, invoked byCirclevirtual dispatchimplicit call
The order in which destructor bodies run when a Circle is destroyed through a Shape pointer. The derived destructor runs first, and the base destructor runs as the chain continues.

What Is Left Behind Without a Virtual Destructor

The difference becomes clearer when the two cases are placed next to each other. Suppose the same Circle is deleted through a Shape pointer, but the base destructor is not declared virtual. The virtual call mechanism is no longer what selects the destructor, so the deletion does not reach the Circle destructor. Only the base layer is cleaned up through that path, and the derived portion of the object is left unreleased. This is exactly the belief the opening section tested, and it fails.

Circle objectone complete objectShape partreached by base destructorCircle membersnot reached through thepointercontainscontains
A Circle object contains a Shape part and its own derived members. When only the base destructor runs, the Shape part is handled but the derived members are not reached through that path.
AspectVirtual base destructorNon-virtual base destructor
Destructor chosen by delete through a Shape pointerCircle destructor, selected by the virtual call mechanismShape destructor, the destructor the pointer's type provides
Derived cleanup of CircleRuns, because the Circle destructor is reachedNot reached through the base pointer
Base cleanup of ShapeRuns, invoked by the Circle destructorRuns as the base destructor
Outcome for the whole objectComplete chain of cleanupDerived portion left unreleased

Deleting a Circle through a Shape pointer, with and without a virtual base destructor

When the Base Destructor Must Be Virtual

The source states that derivation gives programmers great flexibility: a new class can add data members, operations, or both, which is why derived objects often differ substantially from the base class they came from. That same flexibility is why the choice of destructor matters. A derived class that adds members has more to clean up than its base, so destruction has to reach those members too.

The source singles out the abstract class case: a virtual destructor is essential for an abstract class. Because an abstract base class is the interface through which derived objects are normally manipulated and deleted, the base destructor is the one that the pointer's static type exposes. Declaring it virtual is what allows the deletion to reach the proper, most derived destructor.

Mistakes Beginners Make with Base Destructors

  • Common mistake

    Assuming the base destructor is the only one that matters when deleting through a base pointer

    What it looks like

    Deleting a Circle through a Shape pointer and expecting only the Shape destructor message.

    Why it fails

    The source identifies this as the common first assumption and shows that the derived part of the object also needs cleanup.

    Do this instead

    Expect the derived destructor to run first, followed by the base destructor, when the base destructor is virtual.

  • Common mistake

    Leaving the base destructor non-virtual in a class meant to be used through base pointers

    What it looks like

    A Shape base class with an ordinary, non-virtual destructor, used to delete Circle objects.

    Why it fails

    Without the virtual mechanism, the proper destructor is not selected, so the derived portion may be left unreleased.

    Do this instead

    Declare the base destructor virtual, especially in an abstract class.

  • Common mistake

    Treating the destructor order as the only thing that matters

    Why it fails

    The source emphasizes that the whole chain of cleanup depends on starting from the right destructor, not merely on the sequence of messages after it starts.

    Do this instead

    Focus first on which destructor the deletion starts from, then trace the chain of bases and members from there.

Predicting Destruction in a New Hierarchy

EASY

A base class Animal declares a virtual destructor. A class Dog derives from Animal and adds its own destructor that prints Dog destructor. A program creates a Dog, stores its address in an Animal pointer, and deletes it through that pointer. Predict the order of the destructor messages, then explain which destructor the delete starts from and why.

Hints
  • Ask which destructor the virtual call mechanism selects when the object is a Dog, even though the pointer is an Animal pointer.
  • Recall that the proper destructor implicitly invokes the destructor of its base.
  • The expected chain is the derived destructor first, then the base destructor.
MEDIUM

Change the scenario so that Animal's destructor is not declared virtual. Describe what changes about which destructor the delete starts from, and which part of the Dog object is left unreleased.

Hints
  • Compare the starting point of the deletion with and without the virtual call mechanism.
  • Think about which part of the object the Dog destructor is responsible for.

Recap of the Deletion Path

Deleting a derived object through a base pointer is a complete test of the base destructor. The virtual call mechanism routes the deletion to the proper destructor, that destructor does its own cleanup, and it implicitly invokes the bases and members beneath it. Remove the virtual declaration and the path can stop short of the derived part of the object.

Key Takeaways

  • A derived object is usually manipulated through its abstract base class and may be deleted through a pointer to that base class.
  • The virtual function call mechanism selects the proper destructor when delete is applied through a base pointer, so the derived destructor runs rather than only the base destructor.
  • The proper destructor implicitly invokes the destructors of its bases and members, so the whole cleanup chain depends on starting from the right destructor.
  • A non-virtual base destructor can leave the derived portion of the object unreleased, which is why a virtual destructor is essential for an abstract class.

Related concepts

More concepts starting with C