专业编程基础技术教程

网站首页 > 基础教程 正文

Effective C++——条款13:初始化列表中成员顺序和声明顺序相同

ccvgpt 2024-10-10 05:02:43 基础教程 11 ℃

顽固的 Pascal 和 Ada 程序员会经常想念那种可以任意设定数组下标上下限的功能,即,数组下标的范围可以设为 10 到 20,不一定要是 0 到 10。但要?满足?这个要求也很容易,这只需要定义一个? Array类模板:

template<class T>
class Array {
public:
 Array(int lowBound, int highBound);
 ...
private:
 vector<T> data; 
 size_t size; // 数组中元素的数量
 int lBound, hBound; // 下限,上限
};
template<class T>
Array<T>::Array(int low, 
                int high)
: size(high - low + 1),
 lBound(low),  hBound(high),
 data(size)
{}

构造函数会对参数进行合法性检查,以保证 high至少要大于等于low,但这里有个错误:即使上下限值合法,也绝对没人会知道 data 里面会有多少个元素。

Effective C++——条款13:初始化列表中成员顺序和声明顺序相同

规则:类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系。

这里,data第一个被初始化(利用size,但此时size还没有被初始化),所以此时data未知。再看一个例子就好理解为什么规则是如此制定的了。

class Wacko {
public:
 Wacko(const char *s): s1(s), s2(0) {}
 Wacko(const Wacko& rhs): s2(rhs.s1), 
   s1(0) {}
private:
 string s1, s2;
};
Wacko w1 = "Hello world!";
Wacko w2 = w1;

如果成员按它们在初始化列表上出现的顺序被初始化,那 w1 和 w2 中的数据成员被创建的顺序就会不同。一个对象的?析构函数被调用的顺序总是和它们在构造函数里被创建的顺序相反。如果允许上面的情况发生,编译器就要为每一个对象跟踪其成员初始化的顺序,以保证它们的析构函数以正确的顺序被调用。这会带来昂贵的开销,所以?同一种类型的所有对象在创建(构造)和摧毁(析构)过程中对成员的处理顺序都是相同的。

静态数据成员的行为有点像全局和名字空间对象,所以只会被初始化一次。另外,基类数据成员总是在派生类数据成员之前被初始化,所以使用继承时,要把基类的初始化列在成员初始化列表的最前面。(如果使用多继承,基类被初始化的顺序和它们被派生类继承的顺序一致,它们在成员初始化列表中的顺序会被忽略。条款 43关于多继承应考虑哪些方面的问题提出了很多建议。)

总结:请确信初始化列表中成员列出的顺序和成员在类内声明的顺序一致。

最近发表
标签列表