解释此C ++代码中构造函数/析构函数调用的顺序

时间:2016-05-07 13:39:33

标签: c++ constructor order-of-execution

我有这个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()
...

为什么Class2()在创建Class1()之后没有打印p1,例如{{1}}? 这与虚拟继承有关吗?

2 个答案:

答案 0 :(得分:3)

  

为什么在创建例如p1时,在Class1()之后打印Class2()?

由于Class2具有类型为BaseClass的非静态成员对象,因此将在Class2的ctor之前调用其ctor。

根据initialization order

  

初始化顺序

     

1)如果构造函数是针对派生程度最高的类的虚拟基础   类按它们出现的顺序初始化   基类深度优先从左到右遍历基类声明   (从左到右指的是基本说明符列表中的外观)

     

2)然后,直接基类按从左到右的顺序初始化为   它们出现在这个类的基本说明符列表中

     

3)然后,按照以下顺序初始化非静态数据成员   类定义中的声明。

     

4)最后,执行构造函数的主体

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

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

答案 1 :(得分:2)

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

p

这是你要构建的第一个对象,我们称之为BaseClass()

p

BaseClass的{​​{1}}。

Class1()

p的{​​{1}},Class1的子类被构建。

BaseClass

这是BaseClass() 正在构建的id成员。

Class2

现在,最后,Class2() Class2本身。

所以,尽管你不相信,p是在Class2()之后打印的。除非您忘记Class1()也有Class2成员,这是id,并且必须在调用BaseClass构造函数之前构建它。您认为您正在构建第二个Class2::Class2() ed对象的new,但实际构建的是BaseClass成员对象。

P.S。这是BaseClass。在C++中,我们使用C++代替std::cout()。 printf是......上个世纪。