我在C ++中有以下类定义:
class foo {
private:
int a,b,c;
foo(); // constructor
void setup(int x, int y);
void some_function_that_changes_a_b_c();
}
foo::foo() {
a = b = c = 0;
}
void foo::setup(int x, int y) {
foo(); // <-- I use this to make sure a,b,c are initialized
a = x;
b = y; // <-- c is left unchanged!
}
void foo::some_function_that_changes_a_b_c() {
// here's some code that changes variables a,b,c
}
然后我有一个使用这个类的代码:
foo *a = new foo;
a->setup(1,2);
a->some_function_that_changes_a_b_c();
a->setup(5,7); // <-- HERE IS THE PROBLEM
问题是在第二次调用setup()时,它没有运行foo()构造函数来重置我的值或a,b,c,所以c变量保持在调用时的旧值some_function_that_changes_a_b_c(),我用调试器对它进行了测试,看起来在第二次调用时,foo()正在为变量寻址不同的内存空间。
有没有办法解决这个问题?
答案 0 :(得分:4)
在C ++中,构造函数只在构造对象时调用一次,而不再在类方法中调用。在你的代码中
void foo::setup(int x, int y) {
foo(); // ==> this line
}
将创建一个临时foo对象,该对象独立于当前this
对象,因此a
,b
和c
字段this
对象将保持不变。
为了做到你的想法,创建一个类方法,说foo::reset()
,然后从foo::setup()
内部调用它。
答案 1 :(得分:1)
创建对象后,不应调用构造函数。将功能放入受保护的reset()
函数中,该函数从构造函数和setup
函数中调用。
背景:您在foo()
中对setup
的调用不会重新初始化对象,但会创建一个从未使用过的第二个本地对象。通常,除非您完全知道自己在做什么,否则应该避免显式调用构造函数。
答案 2 :(得分:1)
foo(); // <-- I use this to make sure a,b,c are initialized
不幸的是,它并没有这样做。它创建并销毁临时对象。你不能直接调用构造函数;它们仅用于在生命开始时初始化对象。
您可以使用刚刚初步化的对象重新分配对象:
*this = foo();
或者您可以将构造函数的主体移动到reset
函数中,并在需要恢复初始状态时调用它。
我首选的选项是使用单独的对象,而不是尝试重用已修改的对象,并在初始化每个对象时执行所有“设置”:
foo a(1,2);
a.some_function_that_changes_a_b_c();
foo b(5,7); // known to be in a freshly initialised state
答案 3 :(得分:0)
您尝试做的是两阶段初始化。这在C ++中是不必要和笨拙的。你需要实现两件事
在对象创建时调用构造函数
如果你有一个对象说f.setup(1, 2, 3);
,那就意味着构造函数必须已经运行了。
现在:
foo f; // calls foo() with f
f.setup(1, 2, 3); // foo() has arleady been called
foo()
行会创建一个与您正在使用的this
无关的临时对象。
您可以让构造函数获取变量并进行初始化,而不是两个阶段初始化(构造函数,然后是初始化程序)
class foo {
private:
int a,b,c;
public:
foo(int x, int y, int z); // constructor
};
foo::foo(int x, int y, int z)
: a(x),
b(y),
c(z)
{ }
然后使用您想要的值构建
foo f(1, 2, 3);
如果您每次调用setup
时都需要“重置”这些值,那么您最好使用reset
函数或类似函数。尝试自己调用构造函数是可能的,但不是很健康。
void foo::reset() {
a = b = c = 0;
}