当我们需要设置class member的初值时,要么是经过member initialization list ,要么在construcotr内。


一、先讨论必须使用member initialization list的四种情况:

在以下四种情况,为了能够让程序被顺利编译,必须使用member initialization list:

  • 当初始化一个reference mmember时
  • 当初始化一个const member时
  • 当调用一个base class的constructor时,并且基类有一组参数
  • 当调用一个member class的constructor时,并且成员类也有一组参数

虽然在四种情况下,使用构造函数初始化成员,程序可以被正确编译并执行,但是效率不高,举例如下:

 class Word{
String _name;
int _cnt;
public:
//此时是在构造函数内执行数据成员的初始化
Word() { _name = ; _cnt = ;}
};

  上例对应四种情况的第四种,在这里Word constructor会先产生一个临时String object,然后将它初始化,之后以一个赋值运算符将临时性object指定给_name,然后再将那个临时String object摧毁(析构)。以下是编译器对Word constructor扩张的结果:

 //C++伪代码
Word::Word()
{
//调用Stringd的default constructor
_name.String::String(); //产生临时对象
String temp = String(); //memberwise的拷贝_name
_name.String::operator = (temp); //摧毁临时对象 temp
temp.String::~String(); _cnt = ; }

如果在成员初始值列表中进行成员初始化操作,明显更有效率,即如下所示:

 Word::Word: _name(){
_cnt = ; } //将会被扩展成下面形式:
Word::Word()
{
//调用String(int)构造函数
_name.String::String();
_cnt = ;
}

二、讨论下成员初始值列表中初始化的顺序:

  举个例子:   

Word::Word()
: _cnt(),_name() { }

对于上述构造函数,编译器会一一执行初始值列表,以适当顺序(这个顺序是由class中member的声明顺序决定的,而不是initialization list的顺序决定的)在构造函数内安插初始化操作。编译器在constructor的扩展如下:

 Word::Word ()
{
_name.String::String();
_cnt = ;
}

由初始化顺序可能会导致一个意想不到的错误:如下所示:

 class X{
int i;
int j;
public:
X(int val)
:j(val),i(j) {} };

在上述代码中,初始化的顺序应该是先初始i,因为i声明在前,但是因为j一开始没有初值,所以i(j)的结果会导致i无法预知其值。

所以我们可以将i的初始化操作放在构造函数内部,此时initialization list的执行顺序一定在explicit user code之前。如下所示:

X::X(int val)
: j(val) { i = j;}

 三、再来讨论其他两个关于初始化位置的问题:

  其一是、当调用一个成员函数来初始化一个成员的值时,但是请使用构造函数内的member,而不是member initialization list中的member,如下所示:

X::X(int val)
: i(xfoo(val)),j(val) {}

此时和此object相关的this指针,已经被构建妥当,编译器将constructor扩张为如下形式:

 X::X ()
{
i = this->xfoo(val);
j = val;
}

另一情况是还是不要使用派生类的成员函数作为基类构造函数的参数了。不太好

深度探索C++对象模型之第二章:构造函数语意学之成员初始值列表的更多相关文章

  1. 《深度探索C++对象模型》第二章 | 构造函数语意学

    默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一 ...

  2. 深度探索C++对象模型之第二章:构造函数语意学之Copy constructor的构造操作

    C++ Standard将copy constructor分为trivial 和nontrivial两种:只有nontrivial的实例才会被合成于程序之中.决定一个copy constructor是 ...

  3. 深度探索C++对象模型之第二章:构造函数语意学之Default constructor的构造操作

    C++新手一般由两个常见的误解: 如果任何class没有定义默认构造函数(default constructor),编译器就会合成一个来. 编译器合成的的default constructor会显示的 ...

  4. 【C++对象模型】第二章 构造函数语意学

    1.Default Constructor 当编译器需要的时候,default constructor会被合成出来,只执行编译器所需要的任务(将members适当初始化). 1.1  带有 Defau ...

  5. 深度探索C++对象模型之第一章:关于对象之C++对象模型

    一.C和C++对比: C语言的Point3d: 数据成员定义在结构体之内,存在一组各个以功能为导向的函数中,共同处理外部的数据. typedef struct point3d { float x; f ...

  6. 深度探索C++对象模型之第一章:关于对象之对象的差异

    一.三种程序设计范式: C++程序设计模型支持三种程序设计范式(programming paradiams). 程序模型(procedural model) char boy[] = "cc ...

  7. 《深度探索C++对象模型》第一章 | 关于对象

    C++对象模式 非静态数据成员放置在每个类对象内,静态数据成员则被放置在所有类对象之外.静态和非静态的成员函数也被放置在所有类对象之外.每个类产生一堆指向虚函数的指针,放在虚表(vtbl)中.每个类对 ...

  8. 深度探索C++对象模型第四章:函数语义学

    C++有三种类型的成员函数:static/nonstatic/virtual 一.成员的各种调用方式 C with class 只支持非静态成员函数(Nonstatic member function ...

  9. 深度探索C++对象模型之第一章:关于对象之关键词所引起的差异

    ————如果不是为了努力维护与C之间的兼容性,C++远比现在简单的多. 如果一个程序员渴望学习C++,但是他却发现书中没有熟悉的struct,一定会苦恼,将这个主题包含到C++里,可以提供语言转移时的 ...

随机推荐

  1. Java对图片压缩

    背景:图片上传服务器时候的大小限制取消之后,上传图片太大导致前台显示加载缓慢 需求:服务器对接收到的图片进行压缩 方法:1.上传后的文件保存在临时文件夹“/usr/upload/tmp”    2.压 ...

  2. JHipster研究

    liquibase工作原理: master.xml用来维护所有变更记录文件引用 changelog文件夹用来保存具体的变更细节 系统启动时会比较master.xml中include的file,应用差异 ...

  3. keepalived高可用haproxy负载均衡varnish缓存wordpress的动静分离(第一次配置成功)

    haproxy和nginx都可以作为七层和四层反代服务器对外提供服务,此文通过haproxy和keealived配置varnish搭建wordpress的动静分离站点 一.实验环境 五台虚拟机: ha ...

  4. Linux下的Ngnix服务器部署静态页

    一.安装FTP vsftpd 的名字代表”very secure FTP daemon”, 安全是它的开发者 Chris Evans 考虑的首要问题之一.在这个 FTP 服务器设计开发的最开始的时候, ...

  5. BBS论坛 登录功能

    四.登录功能 前端页面html代码: <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  6. dev 中 字符串转中文拼音缩写,对grid列表进行模糊匹配,grid获取焦点行,gridlookupedit控件用拼音模糊匹配下拉选项

    番外篇:. //该方法是将字符串转化为中文拼音的首写字母大写, public static string RemoveSpecialCharacters(string str){try{if (str ...

  7. C:\Windows\System32\drivers\etc中的hosts文件

    这个文件是根据TCP/IP for Windows 的标准来工作的,它的作用是包含IP地址和Host name(主机名)的映射关系,是一个映射IP地址和Host name(主机名)的规定,规定要求每段 ...

  8. 改变this 指向的3种方法

    1.在函数内部声明一个that,然后将this赋值给that, var that=this; 最后用that 代替this使用 <!DOCTYPE html> <html lang= ...

  9. vue 外卖app(2) stylus

    1.安装 npm  install stylus   stylus-loader  --save-dev 安装成功 2.编写样式 <style  lang="stylus" ...

  10. nodejs 模板引擎ejs的简单使用(3)

    1.ejs <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...