我不确定我是否正确地提出了我的问题,所以请随时纠正我。我相信:
初始化列表中的初始化相当于
int a = a;
在构造函数中初始化相当于
int a; a = a;
但我仍然无法弄清楚以下输出的原因:
#include <iostream>
using namespace std;
class test
{
int a,b;
public:
/*
test(int a, int b): a(a), b(b) {} //OUTPUT: 3 2
test(int a, int b) { a = a; b = b;} //OUTPUT: -2 1972965730
test(int c, int d) { a = c; b = d;} //OUTPUT: 3 2
Hence it does work without this pointer. Unless the variable names are same
*/
void print() { cout<<a<<" "<<b<<"\n";}
};
int main()
{
test A(3,2);
A.print();
return 0;
}
编辑:
正如M.M所指出的:等同于a(a)
的是this->a = a
。
有两种解决方法:
test(int a, int b) { this->a = a; this->b = b;}
test(int a, int b) { test::a = a; test::b = b;}
答案 0 :(得分:9)
test(int a, int b) { a = a; b = b;}
这不正确。它对数据成员没有任何作用。它应该是
test(int a, int b) { this->a = a; this->b = b;}
答案 1 :(得分:2)
在初始化列表中,语法是这样的:parens ()
之外的每个变量名都是类成员。 parens里面的内容是在范围内发生的任何事情 - 无论是类成员还是构造函数参数。参数将隐藏类成员。
所以你可以安全地做到:
class MyClass
{
int i;
MyClass(int i): i(i) {}
// ^-must be class member
};
编译器将正确使用 中的参数来初始化parens之外的类成员。
内部发生的事情parens的范围与构造函数体中发生的范围相同。
所以:
class MyClass
{
int i;
MyClass(int i)
{
i = i; // BOTH of those are the parameter i
}
}
名为i
的参数是隐藏名为i
的类成员,因此类成员永远不会在构造函数体中访问。
您必须使用this
明确歧义:
class MyClass
{
int i;
MyClass(int i)
{
// now we set class member i to parameter i
this->i = i;
}
}
所有这些都是在初始化列表的语法中为您完成的:
// v-this parameter is hiding the class member
MyClass(int i): i(i) {}
// ^-must be the class member
初始化列表基本上是:this->i = i
为你做。
如果可能,您应该始终初始化初始化列表中的成员。
答案 2 :(得分:0)
尝试更换
test(int a, int b) { a = a; b = b;}
test(int a, int b) { this->a = a; this->b = b;}
expect(['foo', 'bar']).to.include.members(['foo', 'bar'])
我的编译器(msvc)产生了所需的结果。
答案 3 :(得分:0)
每个功能都引入了一个新范围。将构造函数定义为
时test(int a, int b) { a = a; b = b; }
你隐藏了班级成员。编译器无法知道左a
属于类,右a
是参数。
将构造函数声明为
时 test(int c, int d) { a = c; b = d; }
你没有遇到这个问题,因为没有更多的命名冲突。
在建议的修复中,同样的推理适用:
test(int a, int b) { this->a = a; this->b = b; }
通过使用a
指针明确限定lhs this
是一个类成员,该指针隐式传递给每个成员函数,包括构造函数。但是,此代码不等同于使用初始化列表进行初始化。你的问题是对的:
- 在初始化列表中初始化相当于
int a = a;
- 在构造函数中初始化等效于
醇>int a; a = a;
如果你的成员变量是一些复杂的类,这将产生很大的不同。如果没有初始化列表,您将首先使用默认构造函数创建一个对象,然后为其分配一个新值,而如果使用初始化列表,则只会发生复制构造。
因此,您应该总是更喜欢使用初始化列表:
test(int a, int b): a(a), b(b) {}