解释此 C++ 代码中 constructor/destructor 调用的顺序

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

我有这个 C++ 代码:

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;
}

这是输出:

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

我不明白为什么。我希望输出如下:

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

等等

为什么在创建时Class1()之后不打印Class2(),例如p1? 这跟虚拟继承有关系吗?

让我们逐步构建第一个对象:

new Class2;

这是您正在构建的第一个对象,我们将其命名为 p

BaseClass()

pBaseClass.

Class1()

pClass1,构建了BaseClass的子类。

BaseClass()

这是正在构建的 Class2id 成员。

Class2()

现在,终于 Class2p 本身。

因此,尽管您不这么认为,Class2() 还是打印在 Class1() 之后。除了你忘记了 Class2 也有一个 id 成员,那是一个 BaseClass,而且它也必须在调用 Class2::Class2() 构造函数之前构造。您认为您正在构建第二个 newed 对象的 BaseClass,但真正构建的是 BaseClass 成员对象。

P.S。这是C++。在 C++ 中,我们使用 std::cout 而不是 printf()。 printf() 上世纪如此。

Why isn't Class2() printed after Class1() when creating, for example, p1?

因为Class2有一个类型为BaseClass的非静态成员对象,它的ctor会在Class2的ctor之前被调用。

根据 initialization order:

Initialization order

1) If the constructor is for the most-derived class, virtual base classes are initialized in the order in which they appear in depth-first left-to-right traversal of the base class declarations (left-to-right refers to the appearance in base-specifier lists)

2) Then, direct base classes are initialized in left-to-right order as they appear in this class's base-specifier list

3) Then, non-static data members are initialized in order of declaration in the class definition.

4) Finally, the body of the constructor is executed

对于new Class2;,直接基classClass1及其基classBaseClass将首先被调用。然后将调用类型为 BaseClass 的非静态数据成员 id。最后会调用 Class2 的 ctor 主体。所以你会得到

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