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 ...
随机推荐
- git添加多账户(附带tortoiseGit多账号使用)
近期想在公司电脑上开发自己项目,但是电脑上已经配置过一个gitlab账户了,现在想要把自己的git账户也加进来,方便代码控制. 因为git用的比较少,还不太熟悉,都是网上找资料,边看边学边做,如有不对 ...
- 为什么不建议使用 @Autowired 注解进行注入
在Spring中,Bean的注入一般有三种方式:属性注入.set方法注入.构造器注入. 1.Autowired注入的原理 @Autowired属于属性注入,默认按照类型装配,默认情况下要求依赖的对象必 ...
- PostgreSQL性能优化综合案例 - 2
[调优阶段8] 1. 压力测试 pgbench -M prepared -r -c 1 -f /home/postgres/test/login0.sql -j 1 -n -T 180 -h 172. ...
- 使用git cz 时报模块找不到 使用commitizen init cz-conventional-changelog --save --save-exact --force 又报下面错 头晕
使用git cz 时报模块找不到 使用commitizen init cz-conventional-changelog --save --save-exact --force 又报下面错 头晕 At ...
- Ubuntu安装系统监视器system-monitor并显示在状态栏(火狐浏览器)
system-monitor 使用过Windows 10的朋友们都知道,Windows 10系统自带了一项功能--任务管理器,我们可以通过它方便地查看当前系统的状态,主要包括CPU,内存,硬盘,GPU ...
- Linux与Windows对比
1. 前言 Windows是微软为个人台式机/设备或电脑(PC)开发的一系列操作系统.计算机操作系统(OS).每个操作系统都有一个图形用户界面(GUI),桌面允许用户查看所有文件.视频等.Window ...
- LP1-4:功能图分析方法(白盒测试)
- Tech&W_STU_Resource_bookmark
整合资料 1 architecture: Enterprise integration patterns : https://www.enterpriseintegrationpatterns.com ...
- IDEA的常用快捷键和文档注释
IDEA的常用快捷键 Alt + 回车 导入包,自动修正 Ctrl + N 查找类 Ctrl + Shift + N 查找文件 Ctrl + Alt + N 格式化代码 Ctrl + Alt + O ...
- 重写Collections集合的排序比较CompareTo方法
Collections.sort()使用该方法实际是重写Comparator接口的compare方法实现排序: //传入参数list集合,Comparator接口 T:list的元素类型 //如Lis ...