The Semantics of Constructors——2.4 成员初始化列表
2.4 成员初始化列表(Member Initialization List)
当你写下一个constructor时,就有机会设定class members的初值。要不是经由member initialization list,就是在constructor函数本体之内。
1. 在下列情况下,为了让你的程序能够被顺利编译,你必须使用member initialization list:
- 当初始化一个 reference member时; (引用成员)
- 当初始化一个 const member时; (常量成员)
- 当调用一个 base class的 constructor,而它拥有一组参数时;
- 当调用一个 member class的 constructor,而它拥有一组参数时。
如何理解?
C++ primer: 如果成员是const、引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值。初始化const或者引用类型的数据成员的唯一机会就是通过构造函数初始值。
例如,
class ConstRef{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
};
ConstRef::ConstRef(int ii) {
i = ii; //正确
ci = ii; //错误:不能给const赋值
ri = i; //ri没有被初始化
}
ConstRef::ConstRef(int ii):i(ii),ci(ii), ri(i){} //正确
2. 刚刚的第四种情况,程序可以被正确编译并执行,但是效率不高。
cpp primer: 初始化和赋值的区别: 在很多类中,初始化和赋值的区别事关底层效率问题。前者直接初始化数据成员,后者则先初始化再赋值。

除了效率问题外更重要的是,一些数据成员必须被初始化。建议读者养成使用构造函数初始值的习惯,这样能避免某些意想不到的编译错误,特别是遇到有的类含有需要构造函数初始值的成员时。
class Word {
string _name;
int _cnt;
public:
//进行了赋值操作,没有使用member initialization list, 太初级了。
Word() {
_name = 0;
_cnt = 0;
}
};
在这里,Word constructor会先产生一个临时性的String object,然后将它初始化,之后以一个assignment运算符将临时性object指定给_name,随后再摧毁那个临时性object。
以下是constructor可能的内部扩张结果:
//C++伪代码
Word::Word() {
//调用String的default constructor
_name.String::String();
//产生临时对象
String temp = String(0);
//将temp每个成员都拷贝给_name
_name.String::operator=(temp);
//析构临时对象
temp.String::~String();
_cnt = 0;
}
一个明显更有效率的实现方法:
//使用初始化列表
Word::Word() : _name(0) {
_cnt = 0;
}
它会被扩张成这样:
//C++伪代码
Word::Word() {
//调用String(int) constructor
_name.String::String(0);
_cnt = 0;
}
3. member initialization list 中到底会发生什么事情?
许多C++新手对于list的语法感到迷惑,他们误以为它是一组函数调用。当然它不是!编译器会一一操作initialization list,以适当顺序在constructor之内安插初始化操作,并且在任何explicit user code之前。
4. 用一个成员初始化另一个成员
list中的项目顺序是由class中的members声明顺序决定的,不是由initialization list中的排列顺序决定的。
cpp primer 5th: 成员的初始化顺序与它们在类定义中的出现顺序一致:第一个成员先被初始化,然后第二个,以此类推。构造函数初始值列表中初始值的前后位置关系不会影响实际的初始化顺序。
因为initialization list的项目被放在explicit user code之前。
#include <iostream>
using namespace std;
class X{
public:
int i;
int j;
public:
X(int val):j(val),i(j){} //意欲先初始化j,再用j初始化i,但实际由于i先于j声明,i(j)比j(val)先执行。
};
class Y{
public:
int i;
int j;
public:
Y(int val):j(val){ //为了让j先初始化,应该这样写。
i = j;
}
};
int main(){
X xx(1);
Y yy(1);
cout<<xx.i<<" "<<xx.j<<endl; //4200347 1
cout<<yy.i<<" "<<yy.j<<endl; //1 1
return 0;
}
5.能否调用一个成员函数设定一个成员的初值?

Member function的使用是合法的(当然,我们必须不考虑它所用到的members是否已初始化),这是因为和此 object 相关的 this 指针已经被建构妥当,而constructor 大约被扩充为:

Global objects的内存保证会在程序启动的时候被清为0。Local objects配置于程序的堆栈中,heap objects 配置于自由空间中,都不一定会被清为0,它们的内容将是内存上次被使用后的遗迹。
The Semantics of Constructors——2.4 成员初始化列表的更多相关文章
- C++:用成员初始化列表对数据成员初始化
1.在声明类时,对数据成员的初始化工作一般在构造函数中用赋值语句进行. 例如: class Complex{ private: double real; double imag; public: Co ...
- C++类的成员初始化列表的相关问题
在以下四中情况下,要想让程序顺利编译,必须使用成员初始化列表(member initialization list): 1,初始化一个引用成员(reference member): 2,初始化一个常量 ...
- C++: 类成员初始化列表语法
类的成员初始化列表的初始化的基本语法,类的构造函数还可以运用此语法为其变量初始化: class Class { private: int a; int b; char ch; public: Cl ...
- C++ 成员初始化列表
1.什么是成员初始化列表 #include<iostream> #include<string> using namespace std; class Weapon { pri ...
- C++的成员初始化列表和构造函数体(以前未知)
成员的初始化列表和构造函数在对成员指定初值方面是不一样的.成员初始化列表是对成员初始化,而构造函数,是对成员赋值 成员初始化列表使用初始化的方式来为数据成员指定初值, 而构造函数的函数体是通过赋值的方 ...
- C++中成员初始化列表的使用
C++在类的构造函数中,可以两种方式初始化成员数据(data member). 1,在构造函数的实现中,初始类的成员数据.诸如: class point{private: int x,y;public ...
- (转) C++中成员初始化列表的使用
C++在类的构造函数中,可以两种方式初始化成员数据(data member). 1,在构造函数的实现中,初始类的成员数据.诸如: class point{private: int x,y;public ...
- c++类 用冒号初始化对象(成员初始化列表)
c++类 用冒号初始化对象(成员初始化列表) 成员初始化的顺序不同于它们在构造函数初始化列表中的顺序,而与它们在类定义中的顺序相同 #include<iostream> ; using n ...
- C++ 使用成员初始化列表的一个小坑
注意在成员列表中初始化的顺序并不是列表顺序 而是: 在类中声明的顺序! EventLoop::EventLoop() :looping(false), quit(false),_tid(curThre ...
- 个人学习记录-Cpp基础-成员初始化列表
Translator Translator 参考链接: https://blog.csdn.net/XIONGXING_xx/article/details/115553291http ...
随机推荐
- 梅毒感染者能否应用TNF抑制剂
对于伴发的未经控制的任何严重感染,都不适合使用TNF抑制剂.在1998年国际上首个TNF抑制剂获批治疗类风湿关节炎(RA)以来,这就是广大临床医生和风湿性疾病患者的共识.在临床实践中,需要权衡药物的利 ...
- SpringBoot多数据源以及事务处理
背景 在高并发的项目中,单数据库已无法承载大数据量的访问,因此需要使用多个数据库进行对数据的读写分离,此外就是在微服化的今天,我们在项目中可能采用各种不同存储,因此也需要连接不同的数据库,居于这样的背 ...
- JAVA快速获取网络图片或者URL图片并保存到本地
JAVA快速获取网络图片或者URL图片并保存到本地,直接上代码: package com.xh.service;import org.springframework.stereotype.Servic ...
- 使用 FPM 将源码包转化为rpm包(技巧)
使用 FPM 将源码包转化为rpm包 1.支持的源类型包 dir: 将目录打包成所需要的类型,可以用于源码编译安装的软件包 rpm: 对rpm进行转换 gem: 对r ...
- 0624.python入门
课堂笔记 一 编程语言 什么是编程语言? 上面提及的能够被计算机所识别的表达方式即编程语言,语言是沟通的介质,而编程语言是程序员与计算机沟通的介质.在编程的世界里,计算机更像是人的奴隶,人类编程的目的 ...
- 【面试题】面试官:请你实现一个深拷贝,那如果是正则/set/函数怎么拷贝?
一.面试官灵魂三连问: 你知道哪些拷贝的方法? 让你实现一个深拷贝怎么实现? 那像正则.Set.Map.函数等如何拷贝? 二.浅拷贝方法 自己创建一个新对象,来接收你要重新复制或引用的对象值.如果对象 ...
- 洛谷P8924题解
洛谷 P8924 题解 题目描述 给你一个函数,画出它的函数图像(* 表示经过该点,. 表示不经过该点),大小为 \(n\times m\),其中 \(x\) 的范围是 \([0,n-1]\),\(f ...
- CentOS7 搭建 PXE 安装系统
1. PXE介绍 2. 服务的搭建 2.1 DHCP服务搭建 2.1.1 安装DHCP软件包 2.1.2 修改dhcp配置文件 2.1.3 开启DHCP服务 2.1.4 查看dhcp服务是否开启 2. ...
- Nextjs Contentful GraphQL Vercel Edges
配置contentful 1. 创建免费账号 2. 根据提示进行操作, Content Model - 创建页面属性模板 (personalWebsite) content entry - 根据属 ...
- fastdfs java客户端操作
https://github.com/happyfish100/fastdfs-client-java 到此处下载下来demo 这里采用maven的方式 mvn clean install 上传到本地 ...