7.5 构造函数再探
7.5.1构造函数初始值列表
- 初始化数据成员
构造函数初始列表
sales_data(const string&s):bookNo(s){}
sales_data(const string &s , unsigned n ,double p):bookNo(s),unit_sold(n),revenue(p*n){}
//构造函数的函数体都为空,这是因为这些构造函数的唯一目的就是给数据成员赋初值。一旦没有其他任务需要执行,函数体就为空了。
这两个定义出现新的部分,即冒号以及冒号和花括号之间的代码。这新出现的部分叫做构造函数初始值列表(constructor initialize list)
- 对数据成员进行赋值操作
sales_data(const string &s , unsigned n ,double p){
bookNo = s;
units_sold = n;
revenue = n * p;
}
构造函数的初始值有时必不可少
如果成员时const或者引用的话,必须将其初始化;类似的,当成员属于某种类类型,并且没有默认构造函数,也必须将这个成员初始化。
- 错误的例子:
class ConstRef {
public:
ConstRef(int ii) {
i = ii;
ci = ii;
ri = ii;
}
private:
int i;
const int ci;
int &ri;
};
- 正确的例子
ConstRef(int ii) :i(ii),ci(ii),ri(ii){}
NOTE:如果成员是const,引用,或者属于某种未能提供默认构造函数的类类型。我们必须通过构造函数初始值列表来为这些成员提供初值。
建议:使用构造函数初始值!
成员初始化的顺序
成员初始化的顺序和他们在类中定义的顺序一致。
->【编译器处理完类中全部声明才会处理成员函数的定义,所以和函数的声明顺序无关。】
例子:
class X {
int i;
int j;
public:
X(int val):j(val),i(j){}
};
实际上i先被未定义的j初始化,此时j再被初始化为1。
BEST PRATICE:令构造函数初始值的顺序和成员声明的顺序保持一致。而且尽可能的避免使用某些成员初始化其它成员。
如果可能的话,最好使用构造函数的参数作为成员的初始值,而尽量避免使用同一对象的其它成员。这样的好处就可以不用考虑成员的初始化顺序。
默认实参和构造函数
构造函数中带有默认实参(函数里参数的缺省值,从后向前结合)
7.5.2 委托构造函数(delegating constructor)