Search code examples
c++constructororder-of-execution

Explain order of constructor/destructor calls in this C++ code


I have this C++ code:

class BaseClass {
    int id;
public:
    BaseClass() { printf("BaseClass()\n"); }
    virtual ~BaseClass() { printf("~BaseClass()\n"); }
};

class Class1 : public BaseClass
{
    int id;
public:
    Class1() { printf("Class1()\n"); }
    ~Class1() { printf("~Class1()\n"); }
};

class Class2 : public Class1
{
    BaseClass id;
public:
    Class2() { printf("Class2()\n"); }
    ~Class2() { printf("~Class2()\n"); }
};

class Class3 : virtual public BaseClass
{
    int id;
public:
    Class3() { printf("Class3()\n"); }
    ~Class3() { printf("~Class3()\n"); }
};

class Class4 : public Class3, virtual public Class1
{
    Class3 id;
public:
    Class4() { printf("Class4()\n"); }
    ~Class4() { printf("~Class4()\n"); }
};

int main(int argc, char* argv[])
{
    BaseClass *p = new Class2;
    Class2 *p1 = new Class2;
    Class3 *p2 = new Class3;
    delete p;
    delete p1;
    delete p2;
    return 0;
}

This is the output:

BaseClass()
Class1()
BaseClass()
Class2()
BaseClass()
Class1()
BaseClass()
Class2()
BaseClass()
Class3()
~Class2()
~BaseClass()
~Class1()
~BaseClass()
~Class2()
~BaseClass()
~Class1()
~BaseClass()
~Class3()
~BaseClass()

and I don't understand why. I would expect that the output is the following:

BaseClass()
Class1()
Class2()
BaseClass()
Class1()
Class2()
...

etc.

Why isn't Class2() printed after Class1() when creating, for example, p1? Does this have something to do with virtual inheritance?


Solution

  • Let's go step by step with the first object being constructed:

    new Class2;
    

    This is the first object you're contructing, let's called it p.

    BaseClass()
    

    p's BaseClass.

    Class1()
    

    p's Class1, the subclass of BaseClass gets constructed.

    BaseClass()
    

    This is the id member of Class2 being constructed.

    Class2()
    

    And now, finally, Class2, p itself.

    So, despite your belief otherwise, Class2() is printed after Class1(). Except that you forgot that Class2 also has an id member, that's a BaseClass, and which must also be constructed before the Class2::Class2() constructor gets invoked. You believed that you were seeing the second newed object's BaseClass being constructed, but what was really getting constructed was the BaseClass member object.

    P.S. This is C++. In C++ we use std::cout instead of printf(). printf() is so ...last century.