C++类构造函数初始化列表.docx_第1页
C++类构造函数初始化列表.docx_第2页
C++类构造函数初始化列表.docx_第3页
C++类构造函数初始化列表.docx_第4页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C+类构造函数初始化列表初始化列表的定义 在使用C+编程的过程当中,常常需要对类成员进行初始化,通常的方法有两种:一种是构造函数内对类的成员赋值,一种则是使用初始化列表的构造函数显式的初始化类的成员。 构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如: class CExample public: int a; float b; /构造函数初始化列表 CExample(): a(0),b(8.8) /构造函数内部赋值 CExample() a=0; b=8.8; ; 从技术上说,用初始化列表来初始化类成员比较好,但是在大多数情况下,两者实际上没有什么区别。第二种语法被称为成员初始化列表,之所以要使用这种语法有两个原因:一个原因是必须这么做,另一个原因是出于效率考虑 初始化列表的必要性 初始化和赋值对内置类型的成员没有什么大的区别,像上面的任一个构造函数都可以。但在一些情况下,初始化列表可以做到构造函数做不到的事情: 1、类里面有const类型的成员,它是不能被赋值的,所以需要在初始化列表里面初始化它; 2、引用类型的成员(也就是名字成员,它作为一个现有名字的别名),也是需要在初始化列表里面初始化的,目的是为了生成了一个其名字成员在类外可以被修改而在内部是只读的对象; 3、需要调用基类的构造函数,且此基类构造函数是有参数的; 4、类里面有其他类类型的成员,且这个“其他类”的构造函数是有参数的。 举个例子:设想你有一个类成员,它本身是一个类或者结构,而且只有一个带一个参数的构造函数。 class CExampleOld public: CExampleOld(int x) . ; 因为CExampleOld有一个显式声明的构造函数,编译器不产生一个缺省构造函数(不带参数),所以没有一个整数就无法创建CExampleOld的一个实例。 CExampleOld* pEO = new CExampleOld; / 出错! CExampleOld* pEO = new CExampleOld(2); / OK 如果CExampleOld是另一个类的成员,你怎样初始化它呢?答案是你必须使用成员初始化列表。 class CExampleNew CExampleOld m_EO; public: CExampleNew(); ; / 必须使用初始化列表来初始化成员 m_EO /CExampleNew:CExampleNew() : m_EO(2) 没有其它办法将参数传递给m_EO。 情况3和4其实一样的道理。如果成员是一个常量对象或者引用也是一样。根据C+的规则,常量对象和引用不能被赋值,它们只能被初始化。 初始化列表与构造函数赋值的效率比较 首先把数据成员按类型分类并分情况说明: 1.内置数据类型,复合类型(指针,引用) 在成员初始化列表和构造函数体内进行,两者在性能和结果上都是一样的 2.用户定义类型(类类型) 两者在结果上相同,但是性能上存在很大的差别。 因为编译器总是确保所有成员对象在构造函数体执行之前初始化,所以对于用户自定义类型(类),在初始化列表中只会调用类的构造函数,在构造函数体中赋值就会先调用一次类的构造函数,然后再调用一次类的赋值操作符函数。 显然后者在性能上有所损失,特别对于构造函数和赋值操作符都需要分配内存空间的情况,使用初始化列表,就可以避免不必要的多次内存分配。 举个例子:假定你有一个类CExample具有一个CString类型的成员m_str,你想把它初始化为Hi,how are you.。你有两种选择: 1、使用构造函数赋值 CExample:CExample() / 使用赋值操作符 / CString:operator=(LPCTSTR); m_str = _T(Hi,how are you.); 2、使用初始化列表 CExample:CExample() : m_str(_T(Hi,how are you.) 编译器总是确保所有成员对象在构造函数体执行之前被初始化,因此在第一个例子中编译的代码将调用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 CExample CExample(int x, int y); int m_x; int m_y; ; CExample:CExample(int x, int y) : m_y(y), m_x(m_y) 你可能以为上面的代码将会首先做m_y=y,然后做m_x=m_y,最后

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论