现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

类成员变量初始化列表

2012-09-03 19:19 工业·编程 ⁄ 共 2676字 ⁄ 字号 暂无评论

1) 类成员初始化列表的顺序是很重要的

#include <iostream>

using namespace std;

 

class MemberInitializationList

{

private:

         int i;

         int j;

public:

         MemberInitializationList(int val) : j(val), i(j)        // j(val), i(j)就是所谓的成员初始化列表

         {

         }

 

         inline void printInfo()

         {

                   cout << "i = " << i << ", j = " << j << endl;

         }

};

 

int main(void)

{

         MemberInitializationList MIL(10);

         MIL.printInfo();

       

         return 0;

}

运行结果:

 

j如愿以偿被初始化为10,但是i的值为什么是一个奇怪的数字,而不是意想中的10呢?

答案是有些细微的地方需要注意:成员初始化列表的初始化顺序是有类中的成员声明次序决定的,而不是由initialization list中的排列次序决定的在本例中,先初始化i然后再初始化jinitialization list中的i(j),表明将j的值赋给i,而此时j还没有被初始化,其值不确定,所以i的值也就不能确定,这就是运行结果中为什么i的值比较奇怪的原因了。

 

在任何explicit user code之前,编译器会一一操作initialization list,以适当次序在构造函数内安插初始化操作。

 

需要说明的是,据说除了g++编译器会对这种情况给予warning外,其它的编译器都不会给出相关的警告信息。

 

如果把本例中的构造函数改成:

         MemberInitializationList(int val) : i(val), j(i)

         {

         }

再运行的结果就正确了:

 

 

2) 为什么要使用member initialization list

   根据Stanley LippmanInside C++ Object Model,采用member initialization list的方法的效率比较高,即

         MemberInitializationList(int val) : i(val), j(i)

         {

         }

         的效率要比

         MemberInitializationList(int val)

         {

                   i = val;

                   j = I;

         }

         高。理由是后者会产生临时性的变量,然后要调用赋值运算符赋给真正的变量,再然后摧毁那个临时性的变量。是否真的是这样呢?我们来做一个试验证明之。验证程序如下:

#include <iostream>

#include <time.h>

using namespace std;

 

class MemberInitializationList

{

private:

         int i;

         int j;

public:

//* 编译时,请注释下面两个函数其中一个

         MemberInitializationList(int val) : i(val), j(i)

         {

         }

//*/

/*

         MemberInitializationList(int val)

         {

                   i = val;

                   j = i;

         }

//*/

         inline void printInfo()

         {

                   cout << "i = " << i << ", j = " << j << endl;

         }

};

 

 

int main(void)

{

         //cout << CLOCKS_PER_SEC << endl;

         clock_t start = clock();

         for(int i = 0; i < 3000000; i++)

         {

                   MemberInitializationList* pMIL = new MemberInitializationList(i);

                   delete pMIL;

         }

         clock_t finish = clock();

 

         cout << finish - start << " ms elapsed." << endl;

       

         return 0;

}

结论:VC6VC2005的编译器上,两种方式似乎没有什么区别。或许在别的编译器上有所区别。也就是说,要么微软的编译器对于两种构造函数都使用了临时变量,或者都没有使用临时变量。上述程序没有在别的编译器上试过。

 

3) 调用一个成员函数设定成员变量的初值

#include <iostream>

#include <time.h>

using namespace std;

 

class MemberInitializationList

{

private:

         int i;

         int j;

public:

         MemberInitializationList(int val) : i(setI(val)), j(i)                   // 用成员函数设定成员变量的初始值也是可以的

         {

         }

 

         inline int setI(int i)

         {

                   return i;

         }

 

         inline void printInfo()

         {

                   cout << "i = " << i << ", j = " << j << endl;

         }

};

 

 

int main(void)

{

 

         MemberInitializationList MIL(10);

         MIL.printInfo();

       

         return 0;

} 

给我留言

留言无头像?