在概念上很重要的一点是我们可以认为构造函数的执行过程被分成两个阶段隐式或显式初始化阶段,以及一般的计算阶段计算阶段.由构造函数体内的所有语句构成在计
算阶段中数据成员的设置被认为是赋值而不是初始化.没有清楚地认识到这个区别是程序错误和低效的常见源泉.初始化阶段可以是显式的或隐式的,取决于是否存在成员初始化表.隐式初始化阶段按照声明的顺序依次调用所有基类的缺省构造函数,然后是所有成员类对象的缺省构造函数.
inline Account::
Account()
{
_name = "";
_balance = 0.0;
_acct_nmbr = 0;
}
则初始化阶段是隐式的在构造函数体被执行之前先调用与_name 相关联的缺省string构造函数这意味着把空串赋给_name 的赋值操作是没有必要的.
对于类对象在初始化和赋值之间的区别是巨大的成员类对象应该总是在成员初始化表中被初始化而不是在构造函数体内被赋值缺省Account 构造函数的更正确的实现如下
inline Account::
Account() : _name( string() )
{
_balance = 0.0;
_acct_nmbr = 0;
}
它之所以更正确是因为我们已经去掉了在构造函数体内不必要的对_name 的赋值但是对于缺省构造函数的显式调用也是不必要的下面是更紧凑但却等价的实现
inline Account::
Account()
{
_balance = 0.0;
_acct_nmbr = 0;
}
剩下的问题是对于两个被声明为内置类型的数据成员其初始化情况如何例如用成员初始化表和在构造函数体内初始化_balance 是否等价回答是不对于非类数据成员的
初始化或赋值除了两个例外两者在结果和性能上都是等价的即更受欢迎的实现是用成员切始化表
// 更受欢迎的初始化风格
inline Account::
Account() : _balanae( 0.0 ), _acct_nmbr( 0 )
{ }
两个例外是指任何类型的const 和引用数据成员const 和引用数据成员也必须是在成员初始化表中被初始化否则就会产生编译时刻错误.
每个成员在成员初始化表中只能出现一次初始化的顺序不是由名字在初始化表中的顺序决定而是由成员在类中被声明的顺序决定的
但是在初始化表中出现或者在被隐式初始化的成员类对象中的成员总是在构造函数体内成员的赋值之前被初始化
我们的建议是把用一个成员对另一个成员进行初始化如果你真的认为有必要的代码放到构造函数体内.