Inheritance and Polymorphism

Constructor and Destructor Order

All constructors do not run simultaneously when constructing a derived class object. The base class constructor has to finish first, and then the derived class constructor will begin. While destroying the object, the process is done in the reversed order.

The derived class destructor has to finish first, and then the base class destructor will begin.

All levels of derived classes as well as non static data members follow this rule.

Look at this simple three level derived class. Each derived class prints messages at the constructor and destructor of itself; this will show this process visually.

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base constructed\n";
    }

    // Run this destructor when the object lifetime ends
    ~Base()
    {
        std::cout << "Base destroyed\n";
    }
};

class Middle : public Base
{
public:
    Middle()
    {
        std::cout << "Middle constructed\n";
    }

    ~Middle()
    {
        std::cout << "Middle destroyed\n";
    }
};

class Derived : public Middle
{
public:
    Derived()
    {
        std::cout << "Derived constructed\n";
    }

    ~Derived()
    {
        std::cout << "Derived destroyed\n";
    }
};

int main()
{
    Derived d;
    return 0;
}

Executing this program gives us:

Base constructed
Middle constructed
Derived constructed
Derived destroyed
Middle destroyed
Base destroyed

Construction should start from the base class of the derived hierarchy. While the Derived constructor that we call should not have its own code run yet, the language would first construct the Middle subobject. To construct Middle, it must first construct the Base subobject.

When the Base construction is done, then Middle will be in charge.

After Middle is done, then the Derived class can enter its own body for execution. All this reversal process again happens during destruction. This is to ensure that a derived class can use base class member functions and data members, and that after the derived class destructor is done, the base class is still available for cleaning up purposes.

Members obey this rule as well, but in the order specified in the class definition instead of in inheritance order. Members are constructed after the subobjects of base classes, and in the same sequence that they are declared in the class. During destruction, it will do the inverse: members will be destroyed in reverse order from the declaration list, and only then the destructor of its own class could be invoked. To make this visible, let's look at the following example.

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base constructed\n";
    }

    // Run this destructor when the object lifetime ends
    ~Base()
    {
        std::cout << "Base destroyed\n";
    }
};

class MemberA
{
public:
    MemberA()
    {
        std::cout << "MemberA constructed\n";
    }

    ~MemberA()
    {
        std::cout << "MemberA destroyed\n";
    }
};

class MemberB
{
public:
    MemberB()
    {
        std::cout << "MemberB constructed\n";
    }

    ~MemberB()
    {
        std::cout << "MemberB destroyed\n";
    }
};

class Holder : public Base
{
    MemberA a;
    MemberB b;

public:
    Holder()
    {
        std::cout << "Holder constructed\n";
    }

    ~Holder()
    {
        std::cout << "Holder destroyed\n";
    }
};

int main()
{
    Holder h;
    return 0;
}

The output is:

Base constructed
MemberA constructed
MemberB constructed
Holder constructed
Holder destroyed
MemberB destroyed
MemberA destroyed
Base destroyed

Here the base class is still created first and then the members are created in the top to bottom order declared in the class. At the end, the constructor of Holder is called. Then it destructs the body of ~Holder first and members, in reverse order, then followed by the base class.

The reason for this stringent order is for practicality reasons. In a derived class constructor, it is often necessary to call base class member functions, as well as to access and use base class data members. It is thus required that these entities must be constructed and fully initialized first.

In a similar way, a derived class destructor is allowed to use base class functionality, while it attempts to release its own resources, so the base class must remain constructed until the derived class destructor is completed.

By requiring the base class to be constructed first, and destroyed last, the language can grant those requirements.

In a constructor, if a base class is nominated in the member initializer list, it will be initialized at that point. If the base class is omitted, then the default constructor of the base class will be called implicitly. If some members themselves are class types, then either they should be initialized through the member initializer list or through the default constructors.

The body of the constructor could be called only when the base class subobject and all data members are fully constructed.

The destructor and members then perform actions in the reverse order of that and the object is fully restored to clean states.

Exercise: Constructor and Destructor OrderStarter code, hints and solutionOpenClose
Guided practiceBeginner · 10–15 min

Practice: Constructor and Destructor Order

Work through the mission, reveal hints only when needed, and compare your result with the model solution.

Your challenge

Create another Derived inside a nested block and print Inner block ended afterward. Predict its complete construction and destruction message sequence.

Mission checklist

  1. Run the starter as a baseline, then predict the change requested in Your challenge.
  2. Make that change in your editor; use the lesson-specific hints if you need help.
  3. Compile and run your answer, then compare with the worked solution and explain the result.

Starter program

This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base constructed\n";
    }

    // Run this destructor when the object lifetime ends
    ~Base()
    {
        std::cout << "Base destroyed\n";
    }
};

class Middle : public Base
{
public:
    Middle()
    {
        std::cout << "Middle constructed\n";
    }

    ~Middle()
    {
        std::cout << "Middle destroyed\n";
    }
};

class Derived : public Middle
{
public:
    Derived()
    {
        std::cout << "Derived constructed\n";
    }

    ~Derived()
    {
        std::cout << "Derived destroyed\n";
    }
};

int main()
{
    Derived d;
    return 0;
}

Hints

Hint 1

Constructing Derived first constructs its Base and Middle subobjects. Follow the inheritance chain from the oldest base toward the most-derived constructor body.

Hint 2

At scope exit, list the destructor messages in reverse order: the most-derived part is destroyed before its base parts. There is just one Derived local in main.

Worked solution

A second Derived is created in an inner block. Its Base, Middle, and Derived constructors run in that order. It is destroyed in reverse order at the inner closing brace, before the message announcing that the block ended.

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base constructed\n";
    }

    // Run this destructor when the object lifetime ends
    ~Base()
    {
        std::cout << "Base destroyed\n";
    }
};

class Middle : public Base
{
public:
    Middle()
    {
        std::cout << "Middle constructed\n";
    }

    ~Middle()
    {
        std::cout << "Middle destroyed\n";
    }
};

class Derived : public Middle
{
public:
    Derived()
    {
        std::cout << "Derived constructed\n";
    }

    ~Derived()
    {
        std::cout << "Derived destroyed\n";
    }
};

int main()
{
    Derived d;
    {
        Derived second;
    }
    std::cout << "Inner block ended\n";
    return 0;
}

Example output

Base constructed
Middle constructed
Derived constructed
Base constructed
Middle constructed
Derived constructed
Derived destroyed
Middle destroyed
Base destroyed
Inner block ended
Derived destroyed
Middle destroyed
Base destroyed

0 comments

No comments yet. Be the first.

Add a comment

About CppLearn

CppLearn is an interactive, free reference for modern C++. In each lesson, you'll find out how the language works, rather than just lines of code that you can copy and paste. We cover concepts starting from beginner lessons on fundamentals and proceed to templates, move semantics, smart pointers, and areas that usually trap or scare C++ learners.