寒星轩

There are innumerable stars in the sky, the smallest is me!

用户操作
[即时聊天] [发私信] [加为好友]
李星ID:starlee
207895次访问,排名341好友65人,关注者107
欢迎大家访问我的Blog。
主要是C++,设计模式,面向对象设计方面的技术文章。
starlee的文章
原创 98 篇
翻译 0 篇
转载 45 篇
评论 331 篇
李星的公告
郑重声明

        本BLOG所发表的 原创文章,作者保留一切权利。必须经过作者本人同意后方可转载,并注名作者(StarLee)和出处(CSDN Blog)。
作者Email:
coolstarlee(at)sohu.com
最近评论
陈诚:好象不一样,我这个共两个类,实现类和接口类
深夜才走在路上:实际上使用CLR封送C++类让人很受伤,在mc中有很多C++的特性不能使用,甚至STL都不可用
hfg :错了错了,当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。

不管基类的析构函数是不是virtual ,派生类的析构函数还是会被调用的,区别只是在于基类的析构函数有没有被调用
Forrest Yu:Star Lee:

如果有两个以上的类需要包装,那又应该怎样做呢?
Forrest Yu:CLR 还是很强大的,
一些老的MFC项目可以先手动添加
#include <afx.h>,
其他的可能要加
#include <windows.h>,
然后再用这种方法.
文章分类
收藏
相册
友情链接
houdy的专栏
lijgame的专栏
lyrebing的专栏
禾青谷
存档
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 大师也犯低级错误--《CODE COMPLETE (Second Edition)》中的2处代码错误收藏

新一篇: 一步一步创建VC2005解决方案 | 旧一篇: 我Blog中登上CSDN首页的文章

    最近比较闲,就看了那本放在书架上很久的“砖头”著作--经典的《CODE COMPLETE (Second Edition)》。当然是中文版的,这种大块头的书看英文版是非常累的。
    看到第18章表驱动法Table-Driven-Methods时,感觉这种方法非常好,而我以前也从来没用过这种方法。于是就多看了两眼,没想到就是这多看的两眼,竟然让我在在C++示例代码中发现了大师级作者Steve McConnell犯的2个低级错误!
    在18.2直接访问表Direct Access Tables的例子:灵活的消息格式Flexible-Message-Format Example小节中,有下面这几段代码:

// 第1段(P420)
enum FieldType {
   FieldType_FloatingPoint,
   FieldType_Integer,
   FieldType_String,
   FieldType_TimeOfDay,
   FieldType_Boolean,
   FieldType_BitField,
   FieldType_Last 
= FieldType_BitField
};
 
// 第2段(P422)
AbstractField* field[ Field_Last ];

// 第3段(P422)
field[ FieldType_FloatingPoint ] = new FloatingPointField();
field[ FieldType_Integer ] 
= new IntegerField();
field[ FieldType_String ] 
= new StringField();
field[ FieldType_TimeOfDay ] 
= new TimeOfDayField();
field[ FieldType_Boolean ] 
= new BooleanField();
field[ FieldType_BitField ] 
= new BitFieldField();

// 第4段(P423)
fieldIdx = 1;
while ( ( fieldIdx <= numFieldsInMessages ) && ( fieldStatus == OK ) ) {
   fieldType 
= fieldDescription[ fieldIdx ].FieldType;
   fieldname 
= fieldDescription[ fieldIdx ].FieldName;
   field[ fieldType ].ReadAndPrint( fileName, fileStatus );
}

    我们先来看第1段代码。在C++中,枚举类型的值在默认情况下是从0开始的。所以,代码中的FieldType_FloatingPoint值为0,而FieldType_BitField的值为5。那么FieldType_Last的值也是5。
    再看第2段代码。这样的话,从上面的分析可以得出,第2段代码跟下面的代码是等价的:

AbstractField* field[ 5 ];

    这样的话,第3段代码就会错误!因为,在第3段代码中,向一个只有5个元素空间的数组中放置了6个元素(错误1)。这是明显的下标越界。一个非常低级的错误!
    其实,要想改正这个错误是非常简单的,只要把第1段代码改成下面的样子就行了:

enum FieldType {
   FieldType_FloatingPoint,
   FieldType_Integer,
   FieldType_String,
   FieldType_TimeOfDay,
   FieldType_Boolean,
   FieldType_BitField,
   FieldType_Last
};

    我们再来看第4段代码。这段代码里面的错误就更加低级了。数组field中存放的都是指向对象的指针,而通过指针访问成员函数的话应该是用“->”而不是“.”(错误2),这是任何一个学过C++的人都知道的。可是我们的大师就犯了这么一个低级错误!正确的代码应该是:

fieldIdx = 1;
while ( ( fieldIdx <= numFieldsInMessages ) && ( fieldStatus == OK ) ) {
   fieldType 
= fieldDescription[ fieldIdx ].FieldType;
   fieldname 
= fieldDescription[ fieldIdx ].FieldName;
   field[ fieldType ]
->ReadAndPrint( fileName, fileStatus );
}

    由此可见,就算像Steve McConnell这样的大师级人物也会犯这种非常低级的错误的。
    不过,瑕不掩玉。这一章讲的表驱动法还是非常有用的,而且书中的例子也很好的说明了表驱动法在面向对象设计中优点。另外,总体来看,这也是一本好书。作者把在编程时应该注意的方方面面都进行了叙述,确实是一本很好的软件构建方面的指导书。

    (这里我想多说两句题外话--为什么这么简单的低级错误,译者却没有发现呢?我想可能是对权威的过度迷信吧。也许译者在翻译这本大部头的时候,根本没有去看书中所附的代码。大师也是人,当然也会犯错误。就像编写软件一样,肯定会有bug的,更何况这是一本关于软件构建的书,出现错误也在所难免。在这点上,我觉得内地的译者们应该向台湾的候捷学习。看他翻译的《Inside The C++ Ojecet Model》(深度探索C++对象模型)一书就知道了。他把在翻译时发现的所有错误都列了出来,并且在书中出现错误的地方改正过来,并加以注释。)

    后记:
    我用我蹩脚的英文给Steve McConnell写了封EMail,告诉他书中的这两个错误。没想到,他很快就给我回复了,下面是他回信的截图: 

2007年8月10日更新:

    brucesea在看了这篇文章后在评论里指出了代码中的第3个错误。根据上下文来看,第2段代码中Field_Last应该是FieldType_Last。

发表于 @ 2007年08月09日 09:17:00|评论(loading...)|编辑

新一篇: 一步一步创建VC2005解决方案 | 旧一篇: 我Blog中登上CSDN首页的文章

评论

#benjiam 发表于2007-08-09 15:51:58  IP: 222.68.181.*
fieldType = fieldDescription[ fieldIdx ].FieldType;
fieldname = fieldDescription[ fieldIdx ].FieldName;


??
fieldType = fieldDescription[ fieldIdx ]->FieldType;
fieldname = fieldDescription[ fieldIdx ]->FieldName;


2007-08-10 09:57:24作者回复
书中并没有定义数组fieldDescription的代码,也没有对该数组的说明,因此不能判断数组中的元素是否为指针。所以保留了书中的写法。
#anonymous 发表于2007-08-09 16:37:02  IP: 205.228.118.*
是人就会犯错误,很正常。不过你看书是很仔细阿!
2007-08-10 09:32:54作者回复
说实在的,我在看这本书的时候也没有一行一行的仔细看里面的示例代码。我发现这几处错误是因为因为我觉得这种方法非常好,而我也从来没有用过这种方法,所以多看了两眼(这点我在文章中已经做了说明)。其实,我觉得大家在看别人的代码的时候是非常不仔细的,我们的主要注意力都集中在代码所说明的方法和技巧上了。书中的这短短20多行代码就有3个错误,如果一行一行的仔细看书中其他的示例代码的话,肯定还会找到更多的错误。
#brucesea 发表于2007-08-09 17:33:20  IP: 203.244.221.*
好像还有一个错误。
AbstractField* field[ Field_Last ];
应该是
AbstractField* field[ FieldType_Last ];
2007-08-10 09:00:16作者回复
本来我以为这是我的笔误,又把书中的代码看了一遍,发现这也是书中的错误。
#turingbook 发表于2007-08-10 17:05:22  IP: 125.33.49.*
读书就应该这样。给原作者写信指出错误,更是可嘉。
赞一个。

如果买过图灵出的书,发现错误的,还请多多赐教。
发表评论  


登录
Csdn Blog version 3.1a
Copyright © 李星