在下面的代码中,我在创建基类时为未初始化的类成员赋值。为什么这不会导致运行时错误?
class Foo {
public:
Foo(std::string) {}
};
class Bar : public Foo {
public:
Bar() : Foo(s = f()) {} // assigning to uninitialized class member
void print() {
std::cout << s << std::endl;
}
std::string f() {
return "Some string";
}
private:
std::string s;
};
int main()
{
Bar b;
b.print();
return 0;
}
但是在类Bar中添加另一个成员会在创建Foo类时产生错误:
Class Bar {
// same as above
private:
std::string s;
int a; // adding another member
};
为什么会这样?
答案 0 :(得分:1)
“运行时错误”?分配给未初始化的成员时,没有“运行时错误”。在C ++中,“未初始化”的状态在运行时是不可检测的,这就是为什么它不可能以任何确定的方式处理(如“运行时错误”)。
当您执行类似的操作时,您的代码会显示未定义的行为。离开这种未定义的行为将表现出来是不可预测的。它很容易对完全不相关的因素敏感,比如在课堂上声明另一个成员。这就是它的全部内容。
答案 1 :(得分:0)
我尝试调试你的代码。看来,当你写:
Bar() : Foo(s = f()) {}
尚未正确创建s
对象。因为Foo()
的构造函数调用尚未完成。基本上它处于未定义状态。所以任何行为都是未定义的。
但是这个代码行为并没有被定义:
Bar() : Foo(/*anything*/) {
s = f();
}
因为构造函数调用已完成。
注意:我在msvc11中测试
答案 2 :(得分:0)
当f()执行类时,Bar未初始化,因此成员'a'没有值。有趣的是,这段代码在visual studio 2008中运行,但无论如何这都是不安全的。
勒兹。
答案 3 :(得分:0)
基类和类成员按声明顺序初始化(虚基类不同):
构造函数中初始化的顺序不会改变它。
在你的情况下,Foo是未初始化的,因此Bar和它的成员 - 未定义的行为(s在分配时会有一些垃圾数据)。