这几天都在挣扎。
问题是构造函数调用。
我写了一段代码,如:
#include <iostream>
using namespace std;
class Foo
{
private: int _n;
public:
Foo() { Foo(5);}
Foo(int n) {_n=n; cout << n << endl; }
};
int main()
{
Foo* foo = new Foo();
return 0;
}
当我使用默认构造函数在外部构造Foo对象时:
Foo* f = new Foo();
我认为变量_n是5,但是,它不是。
在Java中没问题,但在c ++中没有。
另外,在Visual C ++ 6 sp 6中,
Foo() {this->Foo(5);}
作品。
但是,这个表达式被gcc / g ++ 4拒绝。
最后,我找到了解决方案。
只需将默认构造函数更改为
即可Foo() {Foo(5);}
到
Foo() { new (this) Foo(5); }
解决了这个问题。
括号中的“this”有什么作用?
答案 0 :(得分:4)
(this)
所做的是在Foo
指向的地方创建一个全新的this
对象(这称为新的展示位置)。您应该只在char
和unsigned char
的数组中使用它,而不是其他任何地方(并且几乎从不存在)。由于您在Foo
已经开始构建的位置构建this
,所以您正在做的是未定义的行为,并且如果您有基类,则会在整个地方泄漏资源。从历史上看,正常的做法只是将初始化移动到私有函数。
class Foo {
public:
Foo() { init(5);}
Foo(int n) {init(n);}
private:
int _n;
void init(int n) {
_n=n;
};
}
在C ++ 11中,构造函数应该能够使用这种语法相互调用,但我不知道哪些编译器支持它。 According to Apache,它得到GCC 4.7和Clang 3.0的支持,但还不支持英特尔C ++和VC ++。
class Foo {
public:
Foo() : Foo(5) {}
Foo(int n) {_n=n;}
private:
int _n;
}
您从Foo() { Foo(5);}
开始的代码开始构建this
,然后使用参数5在堆栈上创建一个全新的Foo
对象,然后销毁它,然后完全考虑自己构建,而不初始化任何自己的值。这就是它编译和运行的原因,但似乎没有做任何事情。
答案 1 :(得分:3)
在C ++ 11中,您可以使用委托构造函数指定它:
Foo() : Foo(5) { }
答案 2 :(得分:1)
括号中的(this)
表示 new 运算符将使用this
的地址作为地址来初始化该类。
非常危险:您在当前对象的构造函数中,并在同一内存空间上调用新的构造函数。 试想一下,如果你从另一个类继承会发生什么!
至于你的问题,你不能从构造函数中调用另一个重载的构造函数。 典型的解决方案是使用初始化类的方法:
class Foo
{
int _n;
public:
Foo() { init(5); }
Foo( int i) { init(i); }
void init(int i) { _n = i; }
};
我在这里遇到了同样的问题:Yet another C++ Object initialization interrogation;随便看看解决方案。
答案 3 :(得分:0)
C ++中的正确语法是
class Foo {
private: int _n;
public:
Foo() : Foo(5) {}
Foo(int n) _n(n) {} // As suggested by another member's edit, initializer lists are preferred
};
或者,C ++允许使用默认参数值,例如
Foo(int n = 5);
这允许你编写一个构造函数而不是两个。
此外,您应该确保了解内联和非内联函数之间的区别。这种Java风格的编程是有效的C ++,但它有其优缺点以及至少一种其他替代方案。
答案 4 :(得分:0)
Foo() { new (this) Foo(5); }
是一个“placement new”运算符,它在预先分配的内存上调用构造函数。
现在,对于你的另一个问题--C ++ 11允许完全相同(从另一个调用构造函数),但早期的标准(特别是MSVC 6使用的标准)没有那么使用那些丑陋的{{ 1}}方法是你的选择。