类成员变量初始化列表(Member Initialization List)
2009-05-05 20:02
393 查看
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然后再初始化j。initialization 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 Lippman的Inside 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;
}
结论:在VC6和VC2005的编译器上,两种方式似乎没有什么区别。或许在别的编译器上有所区别。也就是说,要么微软的编译器对于两种构造函数都使用了临时变量,或者都没有使用临时变量。上述程序没有在别的编译器上试过。
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;
}
#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然后再初始化j。initialization 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 Lippman的Inside 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;
}
结论:在VC6和VC2005的编译器上,两种方式似乎没有什么区别。或许在别的编译器上有所区别。也就是说,要么微软的编译器对于两种构造函数都使用了临时变量,或者都没有使用临时变量。上述程序没有在别的编译器上试过。
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;
}
相关文章推荐
- 类成员变量初始化列表(Member Initialization List)
- C++对象模型(四):class成员初始化列表(Member Initialization List)
- C++初始化成员列表(member initialization list)
- Inside the C++ Model第二讲之 成员初始化列表(Member Initialization List)
- C++对象模型(四):class成员初始化列表(Member Initialization List)
- 利用“member initialization list”初始化类成员
- 成员的初始化表即member Initialization list 。P74~81
- [深度探索C++对象模型]关于成员初始化列表(member initiallization list)
- 构造函数成员初始值列表(member initialization list)
- 构造函数,哪些成员变量一定要通过初始化列表来初始化?
- class中成员变量列表初始化和函数体赋值的区别
- 【C++】类的特殊成员变量+初始化列表
- C++成员变量的初始化顺序如果不使用初始化列表初始化,在构造函数内初始化时,此时与成员变量在构造函数中的位置有关。
- 在初始化列表中,成员变量的初始化顺序是其在类中声明顺序,而非列表中的顺序。
- C++中使用初始化列表比在构造函数中对成员变量赋值更高效
- 构造函数中,哪些成员变量一定要通过初始化列表来初始化
- 成员变量的初始化顺序与变量在类型中的申明顺序相同,而与它们在构造函数的初始化列表中的顺序无关
- C/C++ 通过初始化列表和构造函数内赋值初始化成员变量的区别
- C/C++ 通过初始化列表和构造函数内赋值初始化成员变量的区别
- 构造函数中,成员变量一定要通过初始化列表来初始化的几种情况