中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > C/C++
EffectiveC++2eItem13
作者:lostmouse 时间:2001-12-01 11:25 出处:互联网 责编:chinaitpower
              摘要:EffectiveC++2eItem13

条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同

顽固的Pascal和Ada程序员会经常想念那种可以任意设定数组下标上下限的功能,即,数组下标的范围可以设为10到20,不一定要是0到10。资深的C程序员会坚持一定要从0开始计数,但想个办法来满足那些还在用begin/end的人的这个要求也很容易,这只需要定义一个自己的Array类模板:

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)
{}

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

“这怎么可能?”我听见你在叫。“我小心地初始化了size后才把它传给vector的构造函数!”但不幸的是,你没有——你只是想这样做,但没遵守游戏规则:类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系。用上面的Array模板生成的类里,data总会被首先初始化,然后是size, lBound和hBound。

看起来似乎有悖常理,但这么做是有理由的。看下面这种情况:

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中的数据成员被创建的顺序就会不同。我们知道,对一个对象的所有成员来说,它们的析构函数被调用的顺序总是和它们在构造函数里被创建的顺序相反。那么,如果允许上面的情况(即,成员按它们在初始化列表上出现的顺序被初始化)发生,编译器就要为每一个对象跟踪其成员初始化的顺序,以保证它们的析构函数以正确的顺序被调用。这会带来昂贵的开销。所以,为了避免这一开销,同一种类型的所有对象在创建(构造)和摧毁(析构)过程中对成员的处理顺序都是相同的,而不管成员在初始化列表中的顺序如何。

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

基本的一条是:如果想弄清楚对象被初始化时到底是怎么做的,请确信你的初始化列表中成员列出的顺序和成员在类内声明的顺序一致。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有