2.4 成员初始化列表
对于类成员的初始化,可以采用成员初始化列表或者在构造函数体内两种方式,而且差异不大,但在如下四种情况下,必须使用成员初始化列表(因为效率的原因):
1. 初始化一个引用成员时;
2. 初始化一个const成员时;
3. 调用一个基类的构造函数,但它拥有一组参数时;
4. 调用一个成员类的构造函数,但它拥有一组参数时。
使用成员初始化列表的注意事项:
1. 初始化次序问题:成员初始化列表中不存在函数调用操作,编译器会一一操作初始化列表,根据类中成员的声明次序在构造函数之内安插初始化操作,并且在任何显式用户代码前;
2. 初始化列表中成员次序的依赖性问题:将有依赖性的成员放于函数体内初始化;
3. 构造函数调用类的成员函数问题:如果在构造函数中需要调用类的成员函数,那么一般将函数调用放在构造函数体内,而不是初始化列表处。
4. 基类构造函数调用派生类的成员函数问题:一般避免这种操作,综合例如下:
class X {
private:
int _i;
int _j;
int _k;
public:
X( int val ) : _k( val ), _j( val ) { _i = _j; } //考虑第一种情况的顺序
//而不是X( int val ) : _k( val ), _j( val ), _i( _j ) {} //第二种情况
X( int val ) : _j( val ) { _i = xfoo(val); }
//而不是X( int val ) : _i( xfoo(val) ), _j( val ) { } //第三种情况
int xfoo( int val ) { return val; }
};
class Y : public X {
private:
int _derive;
public:
int derivefunc() { return _derive; }
Y( int val ) : _derive( val ), X( derivefunc() ) {} //第四种情况,应避免
};