遵循 C++ 中的构造函数执行顺序
Following the constructor execution order in C++
我在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
,这意味着只应该调用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)
从我的角度来看,输出:
A::A() // not fully agree
B::B() // not fully agree
A::A()
B::B(int)
D::D(int)
E::E(int)
根据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 的构造函数之前已经调用了相应的构造函数。
- QML按钮点击功能执行顺序
- C++ - scanf() 和 printf() 执行顺序不对
- 递归函数的执行顺序
- 运算符 new 的执行顺序和构造函数的参数
- 如何检查参数包是否具有执行顺序中的确切类型
- std::bind() 参数列表中函子的执行顺序(可能与函数参数的求值顺序无关)
- 了解递归函数的执行顺序
- OpenMP 4.5 任务依赖关系和执行顺序
- 通过调试来检查C 中单行表达式执行顺序的方法
- 遵循 C++ 中的构造函数执行顺序
- 联接线程如何影响主线程中的执行顺序?
- C COUT行为 /执行顺序
- 是定义的函数参数的内部执行顺序
- 强制执行执行顺序
- OpenGL计算着色器中线程的执行顺序
- 按执行顺序创建Pthread
- 逻辑操作员执行顺序
- 如何在使用 std::make_tuple 时避免构造函数的未定义执行顺序
- 提升::thread_specific_ptr/清理与退出执行顺序
- C++ 多线程:执行顺序