template<class T>
class Array {
public:
Array(int lowBound, int highBound);
...
private:
vector<T> data; // 数组数据存储在 vector 对象中
// 关于 vector 模板参见条款 49
size_t size; // 数组中元素的数量
int lBound, hBound; // 下限,上限
};
template<class T>
Array<T>::Array(int lowBound, int highBound)
: size(highBound - lowBound + 1),
lBound(lowBound), hBound(highBound),
data(size)
{}
类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系。用上面的 Array 模板生成的类里,data 总会被首先初始化,然后是 size, lBound 和 hBound。
Array<T>::Array(int lowBound, int highBound): size(highBound - lowBound + 1),lBound(lowBound), hBound(highBound),data(size)
{ }
所以,必须先初始化data(size),使用size初始化data时,size还未被初始化。
总结:类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系
对一个对象的所有成员来说,它们的析构函数被调用的顺序总是和它们在构造函数里被创建的顺序相反。
那么,如果允许上面的情况(即,成员按它们在初始化列表上出现的顺序被初始化发生,编译器就要为每一个对象跟踪其成员初始化的顺序,以保证它们的析构函数以正确的顺序被调用。这会带来昂贵的开销。所以,为了避免这一开销,同一种类型的所有对象在创建(构造)和摧毁(析构)过程中对成员的处理顺序都是相同的,而不管成员在初始化列表中的顺序如何。
实际上,如果你深究一下的话,会发现只是非静态数据成员的初始化遵守以上规则。静态数据成员的行为有点象全局和名字空间对象,所以只会被初始化一次。
1、另外,基类数据成员总是在派生类数据成员之前被初始化,所以使用继承时,要把基类的初始化列在成员初始化列表的最前面。
2、如果使用多继承,基类被初始化的顺序和它们被派生类继承的顺序一致,它们在成员初始化列表中的顺序会被忽略。