我不明白为什么该程序的输出如下。为什么没有编译错误?我以为在尝试构造B时,编译器将找不到名为foo()的函数并报告错误。
#include <iostream>
using namespace std;
struct A{
int a;
A(int i=0) : a(i) { cout << "A" << endl; }
~A() { cout << "Bye A" << endl; }
int foo() { return a; }
};
struct B{
int b;
B(int i=0) : b(i) { cout << "B" << endl; }
~B() { cout << "Bye B" << endl; }
int bar() { return b; }
};
struct C : B, A {
C(int i=0) : B(foo()), A(i) {}
};
int main() {
cout << C(10).bar() << endl;
return 0;
}
输出:
B
A
0
Bye A
Bye B
通常,我想知道何时存在多重继承,父结构的构造和初始化顺序是什么?我还能在课堂上期待类似的行为吗?
非常感谢有关构造函数和析构函数调用顺序的任何解释。
注意:这不是作业。而且,我已经研究了类似的主题,但是在这个问题上什么都没想到。
您通过foo
在对象完全初始化之前进行调用来调用未定义的行为。引用C ++标准中的12.6.2:
可以为正在构造的对象调用成员函数(包括虚拟成员函数10.3)。同样,正在构造的对象可以是运算
typeid
符(5.2.8)或adynamic_cast
(5.2.7)的操作数。但是,如果在所有基类的mem初始化器完成之前,在ctor初始化器中(或直接或间接从ctor初始化器调用的函数中)执行了这些操作,则该操作的结果不确定。[示例:
class A {
public:
A(int);
};
class B : public A {
int j;
public:
int f();
B() : A(f()), // undefined: calls member function
// but base A not yet initialized
j(f()) { } // well-defined: bases are all initialized
};
class C {
public:
C(int);
};
class D : public B, C {
int i;
public:
D() : C(f()), // undefined: calls member function
// but base C not yet initialized
i(f()) { } // well-defined: bases are all initialized
};
—结束示例]
换句话说,按照标准可以:
C(int i=0) : B(), A(i) {
B::b = foo();
}
这将打印10
而不是0
您得到的(可能是其他任何东西,因为那是未定义的行为)。
抛开未定义行为的问题,并解决您的问题,初始化发生的顺序是明确定义的:
在非委托构造函数中,初始化按以下顺序进行:
—首先,并且仅对于最派生类(1.8)的构造函数,虚拟基类按照它们在基类有向无环图的深度优先从左到右遍历时出现的顺序进行初始化,其中“左“从右到右”是基类在派生类base-specifier-list中的出现顺序。
—然后,直接基类按照它们出现在base-specifier-list中的声明顺序进行初始化(与mem-initializers的顺序无关)。
—然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样,无论mem-initializer的顺序如何)。
—最后,执行构造函数主体的复合语句。
[注意:声明顺序是强制执行的,以确保以相反的初始化顺序销毁基础和成员子对象。—尾注]
因此,在您的代码中,初始化顺序为:B
(B::b
),A
(A::a
),C
()。
但是,如下面的注释中所述,但是更改此初始化顺序(例如,通过使用struct C : A, B
而不是struct C : B, A
)不会摆脱未定义的行为。即使零件已初始化A::foo
,在B
零件初始化之前的调用仍未定义A
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句