(5.4-5.9由于开题事宜断更,即日起恢复更新)
前言
当写下一个constructor时我们可以设定class members的初值:它们要么经由Member Initialization List,要么在construtor内部处理(除了4种情况必须使用member initialization list)。
何时必须使用member initialization list
以下四种情况必须使用member initialization list:
- 初始化一个reference member
- 初始化一个const member
- 调用一个base class的constructor,而它拥有一组参数
- 当调用一个member class的constructor,而它拥有一组参数
member initialization list详解
不使用member initialization list
考虑如下程序:
1 | class Word{ |
该程序能够正确编译并执行,只是效率偏低。编译器在执行上述程序扩张代码使之生成一个临时对象,如下所示:
1 | Word::Word(/*this poniter*/){ |
为了保证高效,我们应当做到对任何初始化操作都执行member initialization list。
member initialization list的作用
当构造函数中出现member initialization list后,编译器会一一操作member initialization list,以member声明次序(而非list内部次序)在constructor之内安插初始化操作,次序问题极易引发危险操作,例如:
1 | class X{ |
将会被扩张为:
1 | X::X(int val){ |
member initialization list的疑难点
二探次序
如果member initialization list中的项目被安插到constructor中,会继续保存声明次序吗?
1 | X::X(int val) |
j的初始化操作会安插在explicit user assignment之前或者是之后?答案是initialization list的项目总会被放在explicit user code之前。
initialization list与member function
能否调用一个member function以设定一个member的初值?
1 | X::X(int val) |
答案是可行的。但是…务必使用“存在于constructor体内的一个member”,而非“存在于member initialization list中的member”,来为另一个member设定初值。因为我们无法了解xfoo()对object的依赖性,在确保了xfoo()在constructor内部之后,对于“究竟是哪一个member在xfoo()执行时被设立初值”,就不会造成歧义。
member function的使用是合法的,是建立在和此object相关的this指针已经就位(我们暂且忽略与该member function相关的member),此时原代码大致被扩张为:
1 | X::X(/*this pointer*/){ |
如果一个derived class member function被调用,其返回值作为base class constructor的参数呢?
1 | class FooBar:public X{ |
其扩张结果如下:
1 | FooBar::FooBar(/*this pointer*/){ |
显然,这确实不合时宜。
总结
简单地说,编译器会对initialization list一一处理并且重新排序,以反映出member的声明次序。它会安插部分代码到constructor体内,并置于任何explicit user code之前。