我在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)
答案 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构造函数的调用之前被调用。