C++之父Bjarne Stroustrup:如何学习C/C++语言

C++ 使用的成长及其性质,已经受到学习C++ 的方式的强有力影响。由此可知,如果对应该如何教和学C++ 缺乏认识的话,要想理解它就可能比较困难。如果缺乏这方面的认识,可能就无法理解C++的快速成长的某些方面。

关于应该如何有效地将C++ 教给相对而言的新手,如何使他们能有效地使用学到的东西,这些问题从很早就影响着C++ 的设计。我做了许多教学工作——至少是做了许多教授某些研究者(并不是专业的教育工作者)的工作。我一直设法将自己的想法传播出去,在观察自己和别人所教的人们写出的实际程序方面,有许多成功与失败,这些都对C++ 的设计产生了重要影响。

几年之后逐渐呈现出了一种方式:首先强调一些概念,随后再强调概念之间的关系和主要语言特征。把各个单独语言特征的细节先放下,直到人们需要知道它们的时候再去学习。在这种方式不行的地方,就设法修改语言去支持它。这种相互作用,使这一语言逐渐成长为一种适宜用于设计的更好的工具。

与我一同工作的人以及我教的那些人,基本上都是职业的程序员和设计师,他们需要在工作中学习,不可能拿出几个星期或者几个月去学习新技术。从这里由此也发展出设计C++ 的许多思想,以便使人们能逐步学习它,逐步采纳它的特征。C++ 的组织方式使你能够以大致线性的方式学习它的概念,并在一路上获得实际利益。更重要的是,你的获益大致上可以正比于所花的精力。

我认为,有关程序设计语言、语言特征、程序设计风格等的许多讨论,其实际关注的更多是程序设计语言特征的教育,而不是这些特征本身。对许多人,最关键的问题是:

我没有多少时间去学习新技术和新概念,在这种情况下我怎样才能有效地开始使用C++?

如果某种语言对这个问题的回答比C++ 的更令人满意,人们就会选择那种语言,因为这个程度的程序员通常都有选择权(他们也应该选择)。1993年年初,我在compl. lang.c++ 里对这个问题给出了下面的回答:

“很清楚,使用C++‘最好’是在你对许多概念和技术都有了深入理解,达到了某种随心所欲的状态之后。但要想达到这种状态,你需要通过若干年的学习和实践。下面的方式通常是行不通的,即告诉一个新手(C++ 的新手,而不是一般意义下的程序设计新手),首先取得对C、Smalltalk、CLOS、Pacsal、ML、Eiffel、汇编语言、高性能系统、OODBMS、程序验证技术等的透彻理解,而后在他或她的下一个项目中把这些学过的课程应用到C++上。所有这些课题都值得学习,而且——从长远的观点看——确实也会有帮助,但是实际的程序员(和学生)不可能从他们正身陷其中的事情里抽出若干年的时间,去深入学习和研究程序设计语言和技术。

另外,大部分新手都知道‘一知半解是很危险的事情’,希望能得到一种保证:他们在开始自己的下一个项目之前/之中能拿出时间学到的那一点点东西,将确实能帮助(而不是扰乱或者阻碍那个项目)取得成功。他们也希望能确信,能立即吸取的这一点点新东西可以成为一条坦途的一部分,这条路能指导他们走向他们真正期望的完整理解,而不是某些孤立技巧,向前走什么地方也到不了。

很自然,满足这些准则的途径肯定不止一条,究竟选择哪一条要看个人的背景、当前的需要以及可能花的时间。我认为许多教育培训工作者和在网络上发表意见的人都低估了这个问题的重要性:总的来说,‘教育’一大批人而不是专门关心个别的人,从代价上看起来将会有效得多——也更容易些。

下面考虑几个共性问题:

我对C或C++都不了解,我是不是应该先学习C? 我想做OOP,那么,是不是应该在学习C++ 之前先学Smalltalk? 我在一开始应该把C++ 作为一种OOPL,还是作为一个更好的C? 学习C++ 需要花多少时间?

我不是想说自己有对这些问题的唯一答案。正如前面所言,‘正确的’回答依赖于环境情况,大部分C++ 教科书的作者、教师和程序员都有他们自己的回答。我的回答是基于自己多年用C++ 和系统程序语言做程序设计,教授短的C++ 设计和编程课程(主要是给职业程序员),做C++ 入门和C++ 使用的咨询,讨论C++ 语言,以及自己关于编程、设计和C++ 语言的一般性思考。

我对C或C++ 都不了解,是不是应该先学习C?不,首先学习C++。C++ 的C子集对于C/C++ 的新手是比较容易学的,又比C本身容易使用。原因是C++(通过强类型检查)提供了比C更好的保证。进一步说,C++ 还提供许多小特征,例如运算符new,与C语言对应的东西相比,它们的写法更方便,也更不容易出错。这样,如果你计划学习C和C++(而不只是C++),你不应该经由C那条迂回的路径。为能很好地使用C,你需要知道许多窍门和技术,这些东西在C++ 里的任何地方都不像它们在C里那么重要、那么常用。好的C教科书倾向于(也很合理)强调那些你将来在用C做完整的大项目时所需要的各种技术。好的C++ 教科书则不太一样,强调能引导你去做数据抽象、面向对象的程序设计的技术和特征。理解了C++ 的各种结构,而后学习它们在(更低级的)C里替代物将会很简单(如果需要的话)。

要说我的喜好:要学习C,就用 [Kernighan,1988];要学习C++,就用[2nd]。两本书的优点是都组合了两方面内容:一方面是关于语言特征和技术的指导性的描述,另一方面是一部完整的参考手册。两者描述的都是各自的语言而不是特定的实现,也不企图去描述与特定实现一起发布的特殊程序库。

现在有许多很好的教科书和许多各种各样风格的材料,上面只是我对理解有关概念和风格的喜好。请仔细选择至少两个信息来源,以弥补可能的片面性甚至缺陷,这样做永远是一种明智之举。

我想做OOP,那么,是不是应该在学习C++之前先学Smalltalk?不。如果你计划用C++,那就学C++。各种语言,像C++、Smalltalk、Simula、CLOS和Eiffel等,各有自己对于抽象和继承等关键概念的观点,各语言以略微不同的方式支持着这些概念,也支持不同的设计概念。学习Smalltalk当然能教给你许多有价值的东西,但它不能教给你如何在C++ 里写程序。实际上,除非你有充分时间学习和消化Smalltalk以及C++ 的概念和技术,否则用Smalltalk作为学习工具将导致拙劣的C++ 设计。

当然,如果同时学了C++ 和Smalltalk,能使你取得更广泛领域中的经验和实例,那当然是最理想的。但是那些不可能花足够时间去消化所有新概念的人们常常最后是‘在C++ 里写Smalltalk’,也就是说,去用那些并不能很好适应C++ 的Smalltalk设计概念。这样写出的程序可以像在C++ 里写C或Fortran一样,远不是最好的东西。

常见的关于学习Smalltalk的理由是它‘很纯’,因此会强迫人们去按‘面向对象的’方式思考和编程。我不想深入讨论‘纯’的问题,除提一下之外。我认为一个通用程序设计语言应该而且也能够支持一种以上的程序设计风格(范型)。

这里的问题是,适合Smalltalk并得到它很好支持的风格并不一定适合C++。特别是模仿性地追随Smalltalk风格,将会在C++ 里产生低效、丑陋,而且难以维护的C++ 程序。个中理由很简单,好的C++ 程序所需要的设计应该能很好地借助C++ 静态类型系统的优势,而不是与之斗争。Smalltalk(只)支持动态类型系统,把这种观点翻译到C++ 将导致广泛的不安全性和难看的强制转换。

我把C++ 程序里的大部分强制转换看作是设计拙劣的标志。有些强制转换是很基本的,但大部分都不是。按我的经验,传统C程序员使用C++,通过Smalltalk理解OOP的C++ 程序员是使用强制转换最多的人,而所用的那些种类的转换,完全可以通过更仔细的设计而得以避免。

进一步说,Smalltalk鼓励人们把继承看作是唯一的,或者至少是最基本的程序组织方式,并鼓励人们把类组织到只有一个根的层次结构中。在C++ 里,类就是类型,并不是组织程序的唯一方式。特别的是,模板是表示容器类的最基本方法。

我也极端怀疑一种论断,说是需要强迫人们去采用面向对象的风格写程序。如果人们不想去学,你就不可能在合理的时间内教会他们。按我的经验,确实愿意学习的人从来也不短缺,最好还是把时间和精力用到他们身上。除非你能把握住如何表现隐藏在数据抽象和面向对象的程序设计后面的原理,否则你能做的不过是错误地使用支持这些概念的语言特征,而且是以一种不适当的‘巴罗克’形式[2]——无论在C++、Smalltalk或者其他语言里。

参看《C++ 程序设计语言》(第2版) [2nd],特别是第12章,那里有关于C++ 语言特征和设计之间关系的更多讨论。

我在一开始应该把C++ 作为一种OOPL,还是作为一个更好的C语言?看情况。为什么你想开始用C++?对这个问题的回答应该能确定你走近C++ 的方式,在这里,没有某种放之四海而皆准的道理。按照我的经验,最安全的方式是自下而上地学习C++,也就是说,首先学习C++ 所提供的传统的过程性程序设计特征,也就是那个更好的C子集;而后学着去使用和遵循那些数据抽象特征;再往后学习使用类分层去组织相互有关的类的集合。

按照我的观点,过快地通过早期阶段是很危险的,这样会使忽视某些重要概念的可能性变得非常之大。

例如,一个有经验的C程序员可能会认为C的更好的C子集是‘很熟悉的’,因此跳过了教科书中描述这方面的前100页或多少页。但在这样做时,这个C程序员可能就没看到有关函数的重载能力,有关初始化和赋值之间差异的解释,用运算符new做存储分配,关于引用的解释,或许还有其他一些小特征。在后面阶段它们会不断地跳出来缠住你,而在这时,一些真正的新概念正在复杂的问题中发挥着作用。如果在更好的C中所用的概念都是已知的,读过这100页可能也就只要几个小时的时间,其中的一些细节又是有趣的,很有用的。如果没有读,后面花的时间可能更多。

有些人表达了一种担心,害怕这种‘逐步方式’会引导人们永远去写C语言风格的东西。这当然是一种可能的后果,但是从百分比看,与在教学中采用‘更纯的’语言或者强迫的方式相比,很难说这样做就一定更不值得信任。关键是应该认识到,要把C++ 很好地用作数据抽象和/或面向对象的语言,应该理解几个新概念,而它们与C或者Pascal一类语言并不是针锋相对的。

 

C++ 并不只是用新语法表述一些老概念——至少对于大部分程序员而言不是这样。这也就隐含着教育的需要,而不仅仅是训练。新概念需要通过实践去学习和掌握。老的反复试验过的工作习惯需要重新评价。不再是按照‘老传统的方式’向前冲,而是必须考虑新方式——通常,与按照老方式相比,以新方式做事情,特别是第一次这样做时,一定更困难,也更费时间。

许多经验说明,对大部分程序员而言,花时间和精力去学习关键性的数据抽象和面向对象技术,是非常有价值。并不是必须经过很长的时间才能产生效益,一般在3到12个月就可以。不花这些精力,而只是使用C++,也会有效益,但最大的效益还是要在为学习新概念而花费精力之后——我的疑问是,如果什么人不想花这个精力,那么为什么还要转到C++ 来呢。

在第一次接触C++,或是在许多时间之后又第一次接触它,用一点时间去读一本好的教科书,或者几篇经过很好选择的文章(在The C++ Report和The C++ Journal里有许多这样的文章)。你也可能想看看某些主要的库的定义和源代码,分析其中使用的概念和技术。对那些已经用了一段C++ 的人来说,这也是个好主意,在重温这些概念和技术的过程中可以做许多事情。自C++ 第一次出现以来,在C++ 语言以及与之相关的编程和设计技术方面已经发生过许多事情。将《C++ 程序设计语言》的第1版和第2版做一个简单对比,就足以使人相信这个说法。

学习C++ 需要花多少时间?同样要看情况。依赖于你的经验,也依赖于你所说的‘学习C++’的意思。对大部分程序员而言,学习语法和用更好的C的风格写C++,再加上定义和使用几个简单的类,只要一两周时间。这是最容易的部分。最主要的困难在于掌握新的定义和编程技术,这也是最有意思、最有收获的部分。曾经和我讨论过的大部分有经验的程序员说,他们用了半年到一年半时间,才真正觉得对C++ 适应了,掌握了它所支持的数据抽象和面向对象技术。这里假定他们是在工作中学习并维持着生产——通常在此期间也用着C++的某种‘不那么大胆’的风格做程序设计。如果你能拿出全部时间学C++,就可能更快地适应它。但是,在没有将新的思想和设计应用到真实的项目中之前,这个适应也很可能是骗人的。面向对象的编程和面向对象的设计,基本上是实践性的训练而不是理论训练。只是对一些玩具式的小例子使用或者不使用它,这些思想就很可能演化为一种危险的盲从倾向。

请注意,学习C++,最根本的是学习编程和设计技术,而不是语言细节。在做完了一本教科书的学习工作之后,我会建议一本有关设计的书,例如 [Booch,1991] [4],该书里有一些稍长的例子,用的是5种语言(Ada、CLOS、CLU、C++、Smalltalk和Object Pascal),这样就可能在某种程度上避免语言的偏狭性,而偏狭性已经弄糟了许多有关设计的讨论。在这本书里,我最喜欢的部分就是描述设计概念和例子的那几章。

关注设计方式,与非常仔细地关注C++ 的定义细节(例如ARM,其中包含许多有用的信息,但是没有关于如何用C++ 编程的信息)是截然不同的。把注意力集中到细节上,很容易把人搞得头昏脑涨,以至于根本就用不好语言。你大概不会试着从字典和语法去学习一种外国语吧?

在学习C++ 时,最根本的,应该是牢记关键性的设计概念,使自己不在语言的技术细节中迷失了方向。如果能做到这一点,学习和使用C++ 就会是非常有趣的和收效显著的。与C比较,用一点点C++ 就可能带来许多收获。在理解数据抽象和面向对象技术方面付出进一步努力,你将能得到更多的收获。”

这个观点也不是全面的,受到当前工具和库的状况的影响。如果有了保护性更强的环境(例如包括了广泛的自动的运行时检查)以及一个小的定义良好的基础库,你就可以更早地转到大胆使用C++ 的方面去。这些将能更好地支持从关注C++ 的语言特征到关注C++ 所支持的设计和编程技术的大转移。

分散一些兴趣放到语法上,把一些时间用到语言的技术细节上,也是非常重要的。有些老牌程序员喜欢翻弄这些细节。这种兴趣与不大情愿去学习新的程序设计技术,经常是很难分辨清楚的。

类似地,在每个课程和每个项目里总有这样的人,他们根本不相信C++ 的特征是可以负担得起的,因此在后来的工作中坚持使用自己更熟悉和信任的C子集。只有不多的有关个别C++ 特征和用C++ 写出的系统的执行效率方面的数据(例如,[Russo,1988]、[Russo,1990]、[Keffer,1992]),不大可能动摇这些人长期而牢固的,有关比C更方便的机制是不可能负担的观点。看到这种宣传的量,与语言或工具领域中未得到满足的允诺的量的比较,人们应该对这种说法持怀疑态度,并要求拿出更明显的证据。

在每个课程和项目里也总有另一种人,他们确信效率无关紧要,倾向于用更一般的方式去设计系统,结果是,即使在最先进的硬件上也产生了可观察到的延迟。不幸的是,这种延迟在人们学习C++ 的过程中写玩具程序时很难观察到,因此具有这种性质的问题常常被遗留下来,直到遇到真正的项目。我一直在寻找一个简单但又实际的问题,如果采用一种过分一般的方式去解决,它就能打倒一个很好的工作站。这样的问题将使我能证明带有倾向性的设计的价值,以抵制那些极端的乐观主义者;而通过仔细思考又能使性能大大改善,可以对付过于谨慎和保守的人们。

本文摘自最新上架的《C++语言的设计和演化》。

《C++语言的设计和演化》

[美] 本贾尼·斯特劳斯特卢普,[,Bjarne,Stroustrup,] 著,裘宗燕 译

编辑推荐

1.本书作者Bjarne Stroustrup(本贾尼·斯特劳斯特卢普)被誉为“C++之父”,本书也是作者最重要的专业著作之一;

2.译者裘宗燕,北京大学数学学院信息科学系教授,同时也是知名的程序设计专家,著有《从问题到程序——程序设计与C语言引论》、《数据结构与算法:Python语言描述》等;

3.C++综合性著作:描述C++语言的发展历史、设计理念及技术细节,对C++语言机制的设计和发展的解读是非常难得的宝贵资料。

内容简介

本书是C++的设计者Bjarne Stroustrup关于C++ 语言的最主要著作之一(另一本是《C++程序设计语言》)。在这本书中,作者全面论述了C++ 的历史和发展,C++中各种重要机制的本质、意义和设计背景,这些机制的基本用途和使用方法,讨论了C++ 所适合的应用领域和未来发展前景。本书在帮助人们深入理解C++ 语言方面的地位无可替代,值得每个关心、学习和使用C++ 语言的专业工作者、科研人员、教师和学生阅读。在这本书中,作者还从实践的角度出发,讨论了许多与程序设计语言、系统程序设计、面向对象的技术和方法、软件系统的设计和实现技术等有关的问题,值得每一个关心这些领域及相关问题的计算机工作者和学生们阅读参考。

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值