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.
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?
Reveal 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.
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.
Circle destructor
Shape destructor- 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.
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.
| Aspect | Virtual base destructor | Non-virtual base destructor |
|---|---|---|
| Destructor chosen by delete through a Shape pointer | Circle destructor, selected by the virtual call mechanism | Shape destructor, the destructor the pointer's type provides |
| Derived cleanup of Circle | Runs, because the Circle destructor is reached | Not reached through the base pointer |
| Base cleanup of Shape | Runs, invoked by the Circle destructor | Runs as the base destructor |
| Outcome for the whole object | Complete chain of cleanup | Derived 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 likeDeleting a Circle through a Shape pointer and expecting only the Shape destructor message.
Why it failsThe source identifies this as the common first assumption and shows that the derived part of the object also needs cleanup.
Do this insteadExpect 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 likeA Shape base class with an ordinary, non-virtual destructor, used to delete Circle objects.
Why it failsWithout the virtual mechanism, the proper destructor is not selected, so the derived portion may be left unreleased.
Do this insteadDeclare the base destructor virtual, especially in an abstract class.
Common mistake Treating the destructor order as the only thing that matters
Why it failsThe 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 insteadFocus first on which destructor the deletion starts from, then trace the chain of bases and members from there.
Predicting Destruction in a New Hierarchy
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.
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.