关于初始化C++类成员
副标题#e#
在利用C++编程的进程傍边,经常需要对类成员举办初始化,凡是的要领有两种:
第一种要领:
CMYClass::CSomeClass()
{
x=0;
y=1;
}
第二种要领:
CSomeClass::CSomeClass() : x(0), y(1)
{
}
本文将要探讨这两种要领的异同以及如何利用这两种要领。
从技能上说,第二种要领较量好,可是在大大都环境下,两者实际上没有什么区别。第二种语法被称为成员初始化列表,之所以要利用这种语法有两个原因:一个原因是必需这么做,另一个原因是出于效率思量。
让我们先看一下第一个原因——须要性。设想你有一个类成员,它自己是一个类可能布局,并且只有一个带一个参数的结构函数。
class CMember {
public:
CMember(int x) { ... }
};
因为CMember有一个显式声明的结构函数,编译器不发生一个缺省结构函数(不带参数),所以没有一个整数就无法建设CMember的一个实例。
CMember* pm = new CMember; // 堕落!!
CMember* pm = new CMember(2); // OK
假如CMember是另一个类的成员,你奈何初始化它呢?谜底是你必需利用成员初始化列表。
class CMyClass {
CMember m_member;
public:
CMyClass();
};
// 必需利用初始化列表来初始化成员 m_member
CMyClass::CMyClass() : m_member(2)
{
•••
}
没有其它步伐将参数通报给m_member,假如成员是一个常量工具可能引用也是一样。按照C++的法则,常量工具和引用不能被赋值,它们只能被初始化。
利用初始化列表的第二个原因是出于效率思量,当成员类具有一个缺省的结构函数和一个赋值操纵符时。MFC的CString提供了一个完美的例子。假定你有一个类CMyClass具有一个CString范例的成员m_str,你想把它初始化为"Hi,how are you."。你有两种选择:
CMyClass::CMyClass() {
// 利用赋值操纵符
// CString::operator=(LPCTSTR);
m_str = _T("Hi,how are you.");
}
// 利用初始化列表
// 和结构函数 CString::CString(LPCTSTR)
CMyClass::CMyClass() : m_str(_T("Hi,how are you."))
{
}
#p#副标题#e#
在它们之间有什么差异吗?是的。编译器老是确保所有成员工具在结构函数体执行之前被初始化,因此在第一个例子中编译的代码将挪用CString::Cstring来初始化m_str,这在节制达到赋值语句前完成。在第二个例子中编译器发生一个对CString:: CString(LPCTSTR)的挪用并将"Hi,how are you."通报给这个函数。功效是在第一个例子中挪用了两个CString函数(结构函数和赋值操纵符),而在第二个例子中只挪用了一个函数。
在CString的例子里这是无所谓的,因为缺省结构函数是内联的,CString只是在需要时为字符串分派内存(即,当你实际赋值时)。可是,一般而言,反复的函数挪用是挥霍资源的,尤其是当结构函数和赋值操纵符分派内存的时候。在一些大的类内里,你大概拥有一个结构函数和一个赋值操纵符都要挪用同一个认真分派大量内存空间的Init函数。在这种环境下,你必需利用初始化列表,以制止不要的分派两次内存。
在内建范譬喻ints可能longs可能其它没有结构函数的范例下,在初始化列表和在结构函数体内赋值这两种要领没有机能上的不同。不管用那一种要领,都只会有一次赋值产生。有些措施员说你应该老是用初始化列表以保持精采习惯,但我从没有发明按照需要在这两种要领之间转换有什么坚苦。在编程气势气魄上,我倾向于在主体中利用赋值,因为有更多的空间用来名目化和添加注释,你可以写出这样的语句:
x=y=z=0;
可能
memset(this,0,sizeof(this));
留意第二个片隔离对长短面向工具的。
当我思量初始化列表的问题时,有一个奇怪的特性我应该告诫你,它是关于C++初始化类成员的,它们是凭据声明的顺序初始化的,而不是凭据呈此刻初始化列表中的顺序。
class CMyClass {
CMyClass(int x, int y);
int m_x;
int m_y;
};
CMyClass::CMyClass(int i) : m_y(i), m_x(m_y)
{
}
你大概觉得上面的代码将会首先做m_y=i,然后做m_x=m_y,最后它们有沟通的值。可是编译器先初始化m_x,然后是m_y,,因为它们是按这样的顺序声明的。功效是m_x将有一个不行预测的值。这个例子是存心这样设计来说明这一点的,然而这种bug会很自然地呈现。有两种要领制止它,一个是老是凭据你但愿它们被初始化的顺序来声明成员,第二个是,假如你抉择利用初始化列表,老是凭据它们声明的顺序摆列这些成员。这将有助于消除夹杂。