C++里有个所谓有initializer list,即成员初始化列表.以前对初始化列表了解甚少,
不知道何时应该用何时最好不用.那么现在就总结一点吧.
#include <iostream.h>
class Man
{
public :
Man(int age):m_age(age){};
// Man(int age){m_age = age};
virtual void print(){cout<<"Man's age is "<<m_age<<endl;}
protected:
// const int m_age;
int &m_age;
};
class Boy: public Man
{
public :
Boy(int age):Man(age){};
void print(){cout<<"Boy's age is "<<m_age<<endl;}
};
int main()
{
Man *pMan = new Man(22);
pMan->print();
return 0;
}
在Lippman的C++ Primer里说通过成员初始化列表,类数据成员可以被显式初始化.成
员初始化列表是由逗号分隔的成员,名字实参对.有几个问题要思考,其一,为什么要设
计初始化列表这一功能;其二,什么时候用初始化列表;仅以个人的浅薄闲聊几句而已.
初始化列表是在程序进入构造函数之前执行的,我们要区别出初始化与赋值的不同.
如下:
1)Man(int age):m_age(age){}; //初始化
2)Man(int age){m_age = age}; //赋值
Lippman说二者的区别的重要性取决于数据成员的类型.这里有两种情况:
1) 对于成员类对象
如:class Man
{
Man(string name):m_name(name){};
private:
string m_name;
};
对于string 类的m_name,我们用成员初始化列表来实现其赋值过程而不在构造函数体
内写诸如m_name = name;的赋值语句.并非后者不行,但效率差别巨大.[c++ primer]
这或许是lippman说"没有清楚认识到这个区别是程序错误和低效的常见源泉."的原因
吧.
2)对于内置类型的数据成员
这里又可以分为两类.其一是必须被初始化的东西.(包括const常量和引用) 其二是除
此之外.
如:
class Man
{
public :
Man(int age):m_age(age){}; //这里也体现了初始化与赋值的不同
// Man(int age){m_age = age}; //不能用赋值的办法
protected:
// const int m_age; //这就是两个特例.
int &m_age;
};
对于除此之外的其它内置类型,两种方法的结果和性能一样.不过据说用初始化表更受
欢迎.
使用初始化列表还存在一种隐含的错误.就是对初始化顺序的认识.
如:
class X{
public:
X(int val):j(val),i(j){};
private:
int i;
int j;
};
以上的初始化就是错误的.因为初始化顺序由类声明的顺序决定的.所以上面应该是初
始化i后j.而i要用没被初始化的j来初始化,于是错误发生.一个办法是:把一个成员对
另一成员的初始化放在构造函数内.
参考: C++ Primer第三版 Lippman 等.