Programming 版 (精华区)

1998.09.28 侯捷发表
 
    每年的 09/28 於我都是一个特殊的日子 -- 不只是因为教师节。今年很特殊地没有
普天同庆,那麽我就写篇文章自己庆祝一下好了。我於今年七月发表了一本着作 <多型
与虚拟> 和一本译作 <深度探索 C++ 物件模型> ,获得很大的回响。这些作品都不是针
对 C++ 的完全初学者所写,但从初阶到高阶为数众多的 C++ guy,热情地表达了他们对
这些主题的喜悦。在许多来信中,我看到一些有趣的现象,也感受到一些值得整理下来
的想法。所以,根据我个人的学习过往、我的教学经验、以及周遭朋友的心得交流,写
下这篇文章,或可为後学者戒。


●<多型与虚拟> 序言节录
首先让我节录 <多型与虚拟> 一书序言:
<多型与虚拟> 序 节录(侯俊杰/松岗/1998/07)
一般而言,C++ 是一个难学易用的语言。
C++ 的难学,初始在於其重重的布幕,布幕之中编译器对我们的程式码做了太多的手脚
,使我们惯於循序思考的工程脑袋一无所措。及长,又面临新的思维模式,使我们必须
扭转惯常的思考习惯。
C++ 的易用则在於其巨大的弹性,能够以多型(polymorphism)、虚拟(virtual)、模
板(template)、泛型(generalization)等种种型式,让既有的码去处理未知的、未
来的资料型态。
当然,易用必须先能用。用不好或不能用的话,「写 C++ 程式」最後就成了只是「使用
 C++ 编译器」,这是大家常拿来彼此调侃的笑话。
在「难学」的背景下,「易用」是使我们依然前仆後继的动力。愈来愈多的大学资讯科
系把 C++ 开在大一课程,这虽然说明 C++ 是多麽地重要,可也苦了资讯新兵们。
其实「难学」的最大症结在於,很难得有一本书,能够一针见血地指出多型与虚拟的重
要性;在我们粗具语法基础之後,直接把我们导引到最核心最重要的思想,并且在建立
这个思想的过程中,提供足够的必要基础。


●困难度之一
「C++ 是个难学易用的语言」,这句话相信很多人心有戚戚。C++ 的学习难度,一在於
语言本身太多的「幕」,一在於 "paradigm shift" (思考模式的移转)。传统循序语
言如 C, Pascal, Basic, Fortran...,除了模样看起来稍有不同,基本上都是函式 
call 来 call 去,大同小异,很容易掌握。你想做的动作,在 code 中都看得一清二
楚。你所看不到的,荦荦大者也不过就是编译器为你的函式加上用以处理堆叠的一小段
码(prologue 和 epilogue),这一小段码基本上做的是 housekeeping 工作,你没看
到也没有关系(更好),并不影响你对程式逻辑的思考。C++ 不一样,C++ 有太多和程
式逻辑息息相关的动作是编译器为我们加上去的。换句话说 C++ 编译器为我们「加码。
如果不识清这一节,学习C++ 有如雾里看花,雾非雾。花非花。编译器为我们的 C++ 
程式加了什麽码呢?很多!物件诞生时 ctor 会被唤起,物件死亡时 dtor 会被唤起。
这都是加码的结果。ctor 中设定vtpr 和 vtbl,这也是加码的结果。new 单一物件时会
产生 memory block cookie,new 物件阵列时会产生一个内部结构记录着 object size 
和 class ctor...,这也都是布幕後的工作。可以说,程式码中看不到而却必须完成的
所有与程式逻辑有关的动作,统统都是 C++ 编译器加码後的结果。当「继承」发生,整
个情况变得稍微复杂起来。「多重继承」又更复杂一些,「虚拟继承」再更复杂一些。
这些布幕後的主题,统可归类为所谓的 C++ object model(物件模型)。如果不知道这
些底层机制,你就只能够把 "make destructors virtual in base classes"(<Effect-
ive C++>, item14)或 "never treat arrays polymorphically" (<More Effective 
C++>, item 3)这类规则硬背下来,却不明白它的道理。用一样东西,却不明白它的道
理,林语堂如是说:『不高明』。只知道 how,不知道 why,侯捷如是说:『不高明』。


●困难度之二
    C++ 的第二个学习难度在於 "paradigm shift"(思考模式的移转)。别说自己设计
 classes 了,光使用别人的 classes,就都是一种思考模式和行为模式的移转。MFC
(或 OWL 或 VCL)programmer 必然甚能够领略并体会我的意思。使用所谓的 applic-
ation framework(一种大型的、凝聚性强的、有着物件导向公共基础建设的 class 
library),你的码和 framework 之间究竟是怎样的关系呢?framework 提供的一大堆
可改写的虚拟函式的意义与价值究竟在哪里呢?为什麽 framework 所设计的种种美好性
质以及各式各样的演算法竟然可以施行於我们自己设计的 class types 身上呢?
framework 被设计时,并不知道我们的存在呀!这正是物件导向中的多型(polymorph-
ism)的威力。稍早所说的 C++ 物件模型,偏属程式设计的低层面;这里所说的思考模
式移转,则是程式设计的高层面。能够把新思维模式的威力发挥得最淋漓尽致的,当推
物件导向的 polymorphism(多型)和 generalization(泛型)。如果你没有使用这两
项特性,等於入 C++ 宝山而空手返。


●反覆 炼,循环震荡
    想像 C++ 是一把用来解决程式问题的刀,要它坚轫,要它锋利,就必须经过多次的
回火,在高热和骤冷之间 炼。初学 C++ 语法(syntax)之後,你应该尽快尝试体验 
polymorphism (大致而言也就是虚拟函式的运用)。等到对 OOP 的精神有了大局掌控
的能力,但对 C++ 的许多小细节不甚清楚,就是回到C++ 物件模型 炼的时机。成长,
是在高阶(polymorphism)和低阶(object model)之间反覆震荡,才能够震荡到更高的
位阶,而不是平平庸庸於中阶(C++ syntax)的一滩死水。


●不要沉沦於 C++ syntax
    100 个人跟我说他懂 C++/OOP,只有 10% 不到可以让我认为他没有胡吹大气。太多
的人,上嘛上不到 polymorphism,下嘛又下不到object model。就这样不上不下地卡在 
C++ 语法层面。大一学了C++,到大四快毕业了,连 virtual functions 是怎麽回事都期
期艾艾支支吾吾说不出个道理。有时候我觉得,太苛责同学也於心不忍,因为同学们事实
上处於一种无知的状态,既不知道 C++/OOP 该怎麽学,也不知道哪些书可以教他们那麽
学。所以,苛责同学,不如责怪老师。众所周知,大学教授泰半是动口不动手,普遍的
心态是「论文第一,升等为要;程式语言?哎,末流!」。「末流」课程通常由教授们轮
流教,谁倒楣谁来教;於是就常常有「下学期要教 C++ 语言了,这学期寒(暑)假赶快
去要本书来恶补」的情况发生。偏偏程式语言这东西,只动口不管用,一定要动手,而且
要常动手。老师自己没有摸到C++/OOP 的精神,学生又能学到什麽?
    有些学校资讯系并不教特定的程式语言,老师们的态度是「语言是一种自己学就好了
的东西嘛,拿到大学殿堂来,哎,不入流」!於是应该好好为学生打下实际基础的课程,
却天马行空地腾云驾雾起来,大谈抽象意念。饱读经书的老师们可能忽略了,一个完全
没有技术基础的学子,要的不是形而上的道,而是形而下的器。我们是先能够欣赏具象画
,还是先能够欣赏抽象画?我们不都是先对毕卡索的画大骂「这是什麽东西」,直到自己
的艺术涵养够丰富了、人生阅练更饱满了、能够举一隅以三隅反了、能够接触类旁通左右
逢源了,才转而能够欣赏甚至进入毕卡索的抽象意境吗?
    老师们各有专长,要老师们来教非彼专长的大班课、基础课,我又觉得似乎也太为难
老师了。那麽,苛责老师,不如责怪学校当局。如果学校当局能够聘请经验老道又有教学
热诚的工程师来教这类实务学科,不是三方皆大欢喜吗?不要说什麽制度僵化啦,难以突
破啦,大学是高度自治区,礼聘几位兼任老师,不全都是系上的权责范围内吗?当学子们
在课程上学不到他要的东西,就只好闭门自修。但是,循序性(sequential)语言尚有自
修学会的可能,物件导向语言嘛,以大学生的程度来讲,我认为自修实在困难,只会修出
个四不像、半瓶水。管不到学校!管不到教授!自求多福的情况下,希望看到这篇文章的
你,知道 C++/OOP 该怎麽学。


●不要沉迷於 C++ semantics 和 C++ object model
    对於底层知识有浓厚兴趣的朋友,下探到 object model 领域,一定会非常开心地在
 object size、object layout、vptr/vtbl、以及许多布幕後的技术之间玩将起来。了解
这些东西,当然是好的,但是由於一探究竟得其奥秘的快感与成就感,使得一些朋友们
在这个层面里「玩」起来了,小地方玩得很精,玩得不亦乐乎,玩得忽略了 C++/OOP 的
最终目标。

最终目标是 polymorphism!

    我要说,在 C++ syntax 以及相对低阶的 C++ semantics 里,不要玩得太过火。过
犹不及,会伤身的。C++ 经典名书内附的一些习题,在我看来颇有点玩得过火的味道。至
於什麽百题精选、题库大成,除了修练基本功之外,都满无趣的东西。
    Programming 应该是一种天马行空的想像力与创意的组合;如果你能够自己想题目,
譬如说实作一个天体运行的 class 体系、或是实作一个生物分类(界门纲目科属种)体
系,不是很有趣吗?准备资料的过程中,查查百科全书,你也因此查到了太阳系九大行星
的几何资料,哈雷慧星的轨道周期,或是黑面琵鹭的「界门纲目科属种」英文名称,这
难道不比钻研於 ++++i 或 ----i 或 *&*&p 之类的头脑体操题目有趣吗?(看过不少这
类好笑题目,没一个记下来,只好胡乱写几个运算式。诸位应该知道我说的那种头脑体
操题目)
    固然,在科学与工程的领域里头,无技术无以为立,但别把自己弄得过於僵化,过於
匠气。僵化与匠气是我们教育体系的最大沉疴。到了高专层次,败象显露无遗。


●名书推荐

如果没有介绍几本好书,我就是为德不卒。
让我再节录 <多型与虚拟> 的二刷感言:
<多型与虚拟> 一版二刷感言 (侯俊杰/松岗/1998/08)... C++ 相关书籍,如天上繁星
,如过江之鲫。广博如四库全书者有之(如 The C++ Programming Language、C++ Pri
mer),深奥宛如山重水复有之(如 Inside The C++ Object Model),独沽一味者有之
(如 C++ Programming Style、More Effective C++),独树一帜者有之(如 The Des
ign and Evolution of C++),另辟蹊径者亦有之(如 STL tutorial Reference Guid
e)。...
以下是我认为你应该要拥有的书籍。有趣的是,我才在自己班上做了一个调查(我教的
是物件导向 Windows 程式设计,学生应该要有良好的 C++/OO 基础),拥有以下 1~5 
本书的人举手。举手人数都很少,而且老是那几位(最高记录是拥有四本)。这让我感
觉,强者恒强,弱者恒弱。悲夫!


1. C++ Primer (3/e), Lippman/A.W./1998
(听说 1999 将有中译本)

2. The C++ Programming Language (3/e), Bjarne/A.W./1997
(听说 1999 将有中译本)
以上两本书是 C++ 经典百科。就内容水平而言,我认为同为瑜亮。 普遍的印象是,第
一本较易接受,第二本涩味稍重。第二本书 作者 Bjarne 是 C++ 语言的创造者,所以
有其权威性。我认识的多 位 C++/OOP 高手,都是两书齐具。

3. Inside The C++ Object Model, Lippman/A.W./1996
(中译本 <深度探索 C++ 物件模型>)
全书讲解 C++ object model,上穷碧落下黄泉。内容很好,层次也高, 可惜原文书大
大小小的错误繁如晨星,阅读时需小心。

4. Effective C++, Meyers/A.W./1992
(印象似有中译本,名称忘了,谁可补充说明?)

5. More Effective C++, Meyers/A.W./1996
(有中译本吗?我不知道,谁可补充说明?)
同一作者的这两本书,专讲 C++ programming 的重要观念,使你的程式 更稳健更有效
率。书中许多观念涉及 C++ object model,与 (3) 书混合看, 如鱼得水。

6. Polymorphism in C++ <多型与虚拟> 侯俊杰/松岗/1998
(没有中译本 -- 它本身就是中文书)
在语法粗具的基础上,直接把读者导引到最核心最重要的思想,并且 在建立这个思想的
过程中,提供足够的必要基础。
我只列出一本中文书,是因为这方面的中文书我看得少,英文书看得多。「恐有遗珠之
憾」这类「八方得体」的话,还是说一下好了 :)。
注意,这些都只是强本固元用来扎基础的书籍而已,要观摩大型程式经验,还有诸如 L
arge Scale C++ Software Design(John Lakos/A.W./1996)可以阅读。
OO 的世界,不止 OOP,还有 OOA/OOD,那又是一缸子的学问和一缸子的书。
--- end

[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:4.081毫秒