遵循C ++中的构造函数执行顺序

时间:2019-07-02 12:55:22

标签: c++ inheritance constructor virtual multiple-inheritance

我在C++中有以下程序:

class A {
public :
    A(){
        cout << "A::A()" << endl;
    }
    A( int x){
        cout << "A::A(int)" << endl;
    }
};

class B : public A {
public :
    B(){
        cout << "B::B()" << endl;
    }
    B( int x){
        cout << "B::B(int)" << endl;
    }
};

class C : public virtual B {
    public :
    C(){
        cout << "C::C()" << endl;
    }
    C( int x){
        cout << "C::C(int)" << endl;
    }
};

class D : public B {
public :
    D(){
        cout << "D::D()" << endl;
    }
    D( int x) : B(x){
        cout << "D::D(int)" << endl;
    }
};


class E : public C, public virtual
D, public virtual B {
public :
    E(){
        cout << "E::E()" << endl;
    }
    E( int x) : D(x){
        cout << "E::E(int)" << endl;
    }
};


int main() {
    E(5);
    return 0;
}

我试图了解要打印的内容。我将尝试解释我的情况。首先,我们叫E(5)。在E(int)构造函数中,我们具有以下语法:E(int x) : D(x)然后应调用D(x)构造函数(而不是继承类class E : public C, public virtual D, public virtual B的构造函数,仅意味着{{1 }}应该不带D(x)来调用。在C(),D(),B()类中,我们需要调用D。这部分我不了解-我们调用了B()构造函数,该构造函数也具有以下语法:D(int),因此应调用D(int x) : B(x)而不是B(x)。如果我们需要使用B()构造函数,即使调用的构造函数B()比调用B(x)构造函数的原因,我们也没有执行E(5)

现在,我接受应该首先调用E()。然后,我们调用B()构造函数并执行它,然后执行A()。当我们到达B()时,我们先呼叫D(x),然后再呼叫B(x),所以到目前为止,我们进行打印:

A()

现在我们需要返回A::A() B::B() A::() B::B(int) D::D(int) 并执行它,但是由于某种原因,调用了E(5)构造函数,但我不明白为什么。我们说过,如果我们使用C()语法,则仅执行E(int x) : D(x)。在这些问题中应遵循哪些规则/算法?

编辑: 预期输出:

D(x)

从我的角度来看输出:

A::A()
B::B()
A::A()
B::B(int)
D::D(int)
C::C()
E::E(int)

1 个答案:

答案 0 :(得分:0)

根据C ++标准(C ++ 17,15.6.2初始化基数和成员,第13页)

  

13在非委托构造函数中,初始化在   以下顺序:

     

(13.1)—首先,并且仅用于最派生类的构造函数   (6.6.2),虚拟基类按它们出现的顺序初始化   在有向无环线的深度优先的从左到右遍历   基类的图形,其中“从左到右”是   基类在派生类中的外观   基本说明者列表。

对于此类声明

class E : public C, public virtual
D, public virtual B {
public :
    E(){
        cout << "E::E()" << endl;
    }
    E( int x) : D(x){
        cout << "E::E(int)" << endl;
    }
};

和此显式函数转换表达式

E(5);

深度优先构造函数是虚拟公共B的默认构造函数。

因此,class B的默认构造函数首先被调用

A::A()
B::B()

然后将转换构造函数D( int )称为

A::A()
B::B(int)
D::D(int)

最后将非虚拟基础class C的构造函数称为

  

(13.2)—然后,直接基类在声明中初始化   它们出现在基本说明符列表中的顺序(无论   记忆初始化的顺序)。

C::C()

然后将控件(在初始化非静态数据成员之后)传递到constructor E的正文和消息中

E::E(int)

输出。

请注意,虚拟继承类的构造函数将被首先调用,并且仅被调用一次。因此,C类的构造函数将不会调用B类的构造函数,因为相应的构造函数已经在C构造函数的调用之前被调用。