C++的沉迷与爱恋(侯捷)

2024-04-14 15:18
文章标签 c++ 侯捷 沉迷 爱恋

本文主要是介绍C++的沉迷与爱恋(侯捷),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:侯捷
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" <Effective C++>, item14 )或 "never treat arrays polymorphically" <More Effective C++>, item 3 )这类规则硬背下来,却不明白它的道理。
用一样东西,却不明白它的道理,林语堂如是说:『不高明』。只知道 how ,不知道 why ,侯捷如是说:『不高明』。

困难度之二

C++
的第二个学习难度在於 "paradigm shift" (思考模式的移转)。别说自己设计 classes 了,光使用别人的 classes ,就都是一种思考模式和行为模式的移转。 MFC (或 OWL VCL programmer 必然甚能够领略并体会我的意思。

使用所谓的 application framework (一种大型的、凝聚性强的、有着物件导向公共基础建设的 class library ),你的码和 framework 之间究竟是怎样的关系呢? framework 提供的一大堆可改写的虚拟函式的意义与价值究竟在哪里呢?为什麽 framework 所设计的种种美好性质以及各式各样的演算法竟然可以施行於我们自己设计的 class types 身上呢? framework 被设计时,并不知道我们的存在呀!

这正是物件导向中的多型( polymorphism )的威力。

稍早所说的 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++ Primer ),深奥宛如山重水复有之(如 Inside The C++ Object Model ),独沽一味者有之(如 C++ Programming Style More Effective C++ ),独树一帜者有之(如 The Design and Evolution of C++ ),另辟蹊径者亦有之(如 STL tutorial Reference Guide )。 ...

以下是我认为你应该要拥有的书籍。有趣的是,我才在自己班上做了一个调查(我教的是物件导向 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
(没有中译本 -- 它本身就是中文书)

在语法粗具的基础上,直接把读者导引到最核心最重要的思想,并且 在建立这个思想的过程中,提供足够的必要基础。

我只列出一本中文书,是因为这方面的中文书我看得少,英文书看得多。「恐有遗珠之憾」这类「八方得体」的话,还是说一下好了 :)
注意,这些都只是强本固元用来扎基础的书籍而已,要观摩大型程式经验,还有诸如 Large Scale C++ Software Design John Lakos/A.W./1996 )可以阅读。

OO
的世界,不止 OOP ,还有 OOA/OOD ,那又是一缸子的学问和一缸子的书。

这篇关于C++的沉迷与爱恋(侯捷)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/903330

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

c++中std::placeholders的使用方法

《c++中std::placeholders的使用方法》std::placeholders是C++标准库中的一个工具,用于在函数对象绑定时创建占位符,本文就来详细的介绍一下,具有一定的参考价值,感兴... 目录1. 基本概念2. 使用场景3. 示例示例 1:部分参数绑定示例 2:参数重排序4. 注意事项5.

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

使用C/C++调用libcurl调试消息的方式

《使用C/C++调用libcurl调试消息的方式》在使用C/C++调用libcurl进行HTTP请求时,有时我们需要查看请求的/应答消息的内容(包括请求头和请求体)以方便调试,libcurl提供了多种... 目录1. libcurl 调试工具简介2. 输出请求消息使用 CURLOPT_VERBOSE使用 C

C++实现获取本机MAC地址与IP地址

《C++实现获取本机MAC地址与IP地址》这篇文章主要为大家详细介绍了C++实现获取本机MAC地址与IP地址的两种方式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 实际工作中,项目上常常需要获取本机的IP地址和MAC地址,在此使用两种方案获取1.MFC中获取IP和MAC地址获取