刘佳

C++在类的构造函数中,可以两种方式初始化成员数据(data member)。

1,在构造函数的实现中,初始类的成员数据。诸如:
class point
{
private:
 int x,y;
public:
 point(int m=0,int n=0)
 {
  x=m;
  y=n;
 }
int GetX()
 {
  return x;
 }
 int GetY()
 {
  return y;
 }
};
2,还可以定义初始化成员列表(Initializer list)来初始化成员数据(data member)。
改写构造函数如下:
 point(int m=0,int n=0):x(m),y(n)
 {
 }
这样咋一看没有什么不同,确实,对于上面的这种简单列子来说,也真的没有太大不同。
那我们为什么要用初始化成员列表,什么时候用初始化成员列表来初始化成员数据呢?Lippman的《C++ Primer》中提到在以下三种情况下需要使用初始化成员列表:
一,需要初始化的数据成员是对象的情况;
二,需要初始化const修饰的类成员;
三,需要初始化引用成员数据;
现在分别举例说明:
一,需要初始化的数据成员是对象。
---------------------------
#include <stdio.h>
class point
{
protected:
 int m_x,m_y;
public:
 point(int m=0,int n=0)
 {
  m_x = m;
  m_y = n;
  printf("constructor called!/n");
 }
 point(point& p)
 {
  m_x = p.GetX();
  m_y = p.GetY();
  printf("copy constructor called!/n");
 }
 int GetX()
 {
  return m_x;
 }
 int GetY()
 {
  return m_y;
 }
};
class point3d
{
private:
 point m_p;
 int m_z;
public:
 point3d(point p, int k)
 {
  m_p = p;                              //这里是对m_p的赋值
  m_z=k;
 }
 point3d(int i,int j, int k):m_p(i,j)   // 相当于 point m_p(i,j)这样对m_p初始化
 {
  m_z=k;
 }
 void Print()
 {
  printf("%d,%d,%d /n",m_p.GetX(),m_p.GetY(),m_z);
 }
};
---------------------------------------
上述代码中Point3d是一个3D坐标,他有一个point的2D坐标和一个成员组成。
我们现在想定义一个3D坐标p3d,可以这样实现:
void main()
{
 point p(1,2);    //先定义一个2D坐标
point3d p3d(p,3);
p3d.Print();
}
从point3d实现体可以看出,我们是通过对m_p进行赋值,这样不仅调用copy constructor产生临时对象而且是对m_p的一个赋值操作。
而如果使用成员初始化列表,我们则可以这样:
void main()
{
 point p(1,2);
point3d p3d(1,2,3);
p3d.Print();
}
p3d中的point型成员是通过调用初始化的方式构建的。由于对象赋值比初始化要麻烦的多,因此也带来的性能上的消耗。(可以参见Scott Meyers著《effective C++》条款12)。
这也是我们在对成员数据是对象成员的采用初始化列表进行初始始化的主要原因。
二,需要初始化const修饰的类成员;
三,需要初始化引用成员数据;
对于类成员是const修饰,或是引用类型的情况,是不允许赋值操作的,(显然嘛,const就是防止被错误赋值的,引用类型必须定义赋值在一起)因此只能用初始化列表对齐进行初始化。
上面两点比较好明白,可以用一个例子加以说明:
-------------------------------------
#include <stdio.h>
class base
{
private:
 const int a;
 int& b;
public:
// base(int m, int n)
// {
//  a = m;
//  b = n;
// }
base(int m, int n):a(m),b(n)
 {}
};
void main()
{
 base ba(1,2);
}
---------------------------
上面红色的部分初始化的方式是不允许的通不过编译,通过初始化列表则可以很好的定义。
waret : http://www.dnbcw.com/biancheng/java/mkxa197808.html 

构造函数初始化列表

作者:waret 和java相关

简介:这是构造函数初始化列表的详细页面,介绍了和java,JavaEye 构造函数初始化列表有关的知识、技巧、经验,和一些java源码等。

构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。例如:

Example::Example() : ival(0), dval(0.0)

{

//ival 和dval是类的两个数据成员

}

上面的例子和下面不用初始化列表的构造函数看似没什么区别:

Example::Example()

{

ival = 0;

dval = 0.0;

}

二者的区别在于:上面的构造函数(使用初始化列表的构造函数)显示的初始化类的成员;而没使用初始化列表的构造函数是对类的成员赋值,并没有进行显示的初始化。但有时必须用带有初始化列表的构造函数:

(1)成员类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。

(2)const成员或引用类型的成员。因为const对象或引用类型只能初始化,不能对他们赋值。

(3)在继承里面,只有初始化列表可以构造父类的private成员。

因为类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)

初始化列表的成员初始化顺序: C++初始化类成员时,是按照声明的顺序初始化的,而不是按照出现在初始化列表中的顺序。

class CMyClass

{

CMyClass(int x, int y);

int m_x; int m_y;

};

CMyClass::CMyClass(int x, int y) : m_y(y), m_x(m_y) { }

编译器先初始化m_x,然后是m_y,因为它们是按这样的顺序声明的。结果是m_x将有一个不可预测的值。有两种方法避免它,一个是总是按照你希望它们被初始化的顺序声明成员,第二个是,如果你决定使用初始化列表,总是按照它们声明的顺序罗列这些成员。这将有助于消除混淆。

转载于:https://www.cnblogs.com/wbb2109/archive/2011/04/29/2263695.html

lt;转载自刘佳ID:freedom0203和waretgt; C++中成员初始化列表的使用相关推荐

  1. B表中的pid对应A表中id,查询A表中数据,根据b表中对应a表中该id的数据数目排序...

    B表中的pid对应A表中id,查询A表中数据,根据b表中对应a表中该id的数据数目排序 select a.*,count(*) as c from a left join b on a.id=b.ai ...

  2. 【MOS】中文文档列表 - Oracle Database (文档 ID 1533057.1)

    中文文档列表 - Oracle Database (文档 ID 1533057.1) 类型: 状态: 上次主更新: 上次更新: ANNOUNCEMENT PUBLISHED 2017-2-23 201 ...

  3. 【转载】c#类的成员初始化顺序

    作者:彭白洋 创建于:2009-01-15 出处:http://www.cnblogs.com/siceblue/archive/2009/01/15/1376430.html  收录于:2013-0 ...

  4. 通过ID在JavaScript对象数组中查找对象

    本文翻译自:Find object by id in an array of JavaScript objects I've got an array: 我有一个数组: myArray = [{'id ...

  5. 企业微信怎么输入服务器id,系统账号绑定企业微信成员id

    原标题:系统账号绑定企业微信成员id 场景 在白码系统中需要使用各种接口对接企业微信时,发现需要使用企业微信的成员id,比如创建日程.获取打卡数据等接口,所以在此之前需要先将成员id与白码系统中的用户 ...

  6. 为什么要把id存到redis的key中_干货|mysql:exists还是in?哪个性能好?为什么?

    作者:wanber 链接:https://blog.nowcoder.net/n/fc944cca2eeb410a876f742f6d48662d 来源:牛客网 在项目中经常会用到in和exists, ...

  7. App ID申请(将项目中的ID向苹果申请)

     最近公司移动端大佬离职了,我一个做Java的接手了移动端任务,小白很无奈啊,百度了iOS开发相关知识,下面引用大神的文章做一篇笔记,原文地址是:https://www.jianshu.com/p/e ...

  8. ensembl数据库BioMart使用,查找转录本ID在ensembl与refseq中的对应关系

    如何查找 转录本ID在ensembl与refseq中的对应关系 Ensembl数据库地址: http://grch37.ensembl.org/index.html 进入BioMart 选择DataS ...

  9. python中id函数的用法_Python中的id()函数

    在本文中,我们将学习id()Python 3.x中函数的用法和实现.或更早.它存在于Python标准库中,在执行代码之前会自动导入. 语法:id() 返回值:类型的标识值 该函数正好接受一个参数,即必 ...

最新文章

  1. [转]xml解析工具的效率比较QDomDocument、TinyXml-2、RapidXml、PugiXml
  2. 视频监控成AI芯片主战场,海康威视和大华股份占据半壁江山
  3. PAT A1065 A+B and C (64bit) (20 分)
  4. 向量与向量的叉积和向量与矩阵的叉积数学表达式与python 实现
  5. 1046 Shortest Distance (20 分)【难度: 简单 / 知识点: 前缀和 / 破环成链】
  6. Socket套接字 =======================
  7. PyTorch官方教程中文版:Pytorch之图像篇
  8. 互联网从业者平均年薪19万,程序员最高!
  9. 路由器snmp配置_S7503E V7 snmpv3典型组网配置案例(与IMC联动)
  10. vivo6.0系统怎么样不用root激活XPOSED框架的方法
  11. 和pythondjango后端_webGIS实践:4_0_python django后端搭建web工程
  12. Django-Model操作数据库(增删改查、连表结构)
  13. php中$t=date()函数参数意义及时间更改
  14. Visio2013里面的大括号
  15. UDS/OBD DTC(诊断故障码)格式解析
  16. python多进程协同_简单谈谈python中的多进程
  17. Linux TCP Timestamps 没鸟用
  18. neural networks logistic regression 神经网络逻辑回归
  19. QT中文字体显示以及字体大小不能改变的问题
  20. vscode默认输出到调试控制台

热门文章

  1. 正态分布的前世今生:正态分布的进一步发展
  2. JAVA偏向锁的什么时候释放_​java偏向锁,你还没上车,它就要被去掉了
  3. 图像局部特征(十六)--SimpleBlobDetector
  4. Windows下VB6.0开发——VB程序断点调试与顺序执行不一致问题(通信原因)
  5. 计算机械效率的公式怎么读,机械效率公式总结
  6. 文件分配表(File Allocation Table)入门
  7. Hive 入门练习题
  8. 全面详解c语言使用cJSON解析JSON字符
  9. day23_内置函数(__del__ item系列 ,模块)
  10. 1019 数字黑洞 (20)