关于构造方法的一个有趣的问题:初始化队伍
下面这段代码是有问题的,问题当然是关于构造方法:
1: class A
2: {
3: private:
4: int i;
5: int j;
6: public:
7: A ( int val )
8: :j ( val ), i ( j )
9: {}
10:
11: void print(){
12: cout<<i<<" "<<j<<endl;
13: }
14: };
15:
16: int main()
17: {
18: A a(1);
19: a.print();
20: return 0;
21: }
构造方法的实现很简单:先将val的值赋给j,再将j赋值给i。
但事实上并没有达到这个效果。
这里有一个初始化队伍的问题。初始化队伍这里指的就是构造方法中冒号后面的部分。
编译器在处理初始化队伍时,会根据成员变量的声明次序重新排序。也就是说,虽然构造方法是先对j进行初始化,但是,根据i和j的声明次序,实际上是先对i初始化,然后再对j进行初始化。这样一来,由于j还未初始化,所以最终的结果是i的值并不是val。下面是我在visual studio 2010下输出的结果:
-858993460 1
这种问题是很难发现的,要修正很简单,只需要将构造方法写为:
1: A ( int val )
2: :j ( val )
3: {
4: i = j;
5: }
这里,还存在另一个知识点:执行初始化队伍( j(val) )在执行任何显式代码(explicit user code)之前,这里指的就是“i=j”。所以,就是先令j=val,然后令i=j。
输出的结果自然就是:
1 1
所以建议,如果是用一个数据成员对另一个数据成员进行初始化,即赋值,最好是把这样的代码写在构造函数体内(显式代码)。
参考文献:《深度探索C++对象模型》