本书是为有一定C++开发经验的人员设计和编写的。为了更加精通C++程序设计,我们不仅要深刻地了解如何学习一种新的程序设计语言,而且更重要的是如何利用这种语言高效地解决实际的软件问题。
学习程序设计语言
通常,在语言手册中,并非读者所要了解的东西都能完全描述出来。其实做任何事情都不可能面面俱到,学习程序设计语言也是这样。学习语言的语法可以使我们朝着更深层次的思维方向理解,但这仅仅是深化理解的开始,更重要的是大多数我们系统所要建立的程序结构的准则,应当表述设计概念的风格和习惯用法。
风格应当把优点和技能区分开来。一种高效的主体风格或者是高效的程序设计风格来自于个人的经验和在其他经验基础之上建立起来的风格。软件工程师应当知道如何选择与应用相匹配的程序设计语言,以编写出优秀的、结构良好的程序。为了达到这个层次的水平,我们需要超越一些规则,抛弃死记硬背的学习方式,最后达到概念和结构上的抽象,这就是本书所说的“高级”的含义所在。
程序设计的准则、约定和概念推动了所建立的系统结构,使我们更加清晰地了解到系统的模型是如何建立的。问题分解和系统组合的模型是一种范型,是把现实世界分为可管理部分的模式。C++语言是多重范型语言,C程序员使用C++就好像使用最好的C一样,面向对象主张事物的多态性。事实上,不同的方法通常必须表达对软件问题高效、优美的问题解。
学习程序设计语言就像学习一种自然语言一样,基本的语法知识可以让程序员在编写过程时更加简单,程序编写得也更加简洁,好像一个人仅从几千个词语的字典中就可以撰写出美丽动人的童话故事一样。
但学习语法和基本语义是需要花费相当多的时间的,不可能一下子就挖出个金娃娃。语言的奥妙属于另一类复杂的问题。学习程序设计语言与学习自然语言的差别就在于要学习语言的习惯用法。例如,在C本身不存在把构造while(*cpi++=*cp2++);作为基本构造块来处理,而一个不熟悉这种构造的程序员却不曾发觉。
在程序设计中,像自然语言一样,重要的习惯用法,或者说好的习惯用法可以大大减轻程序员的工作量,就好像在任何一种语言中习惯用法丰富了相互之间的交流一样。程序设计的习惯用法是可重用程序设计的“表述”。在同样的意义下,类是设计和代码的可重用单位。简单的习惯用法(像上面while循环)是约定的表示,但很少是程序设计的核心。本书集中在习惯用法上,它影响到如何在整体结构中使用C++语言并实现一种设计。这种习惯用法大大改善了对问题的洞察力,导致更加简单的习惯用法的出现。通常,习惯用法引入了某种复杂性,但只要编写一次就可以随处运行了。一旦构造成功,程序设计语言习惯用法便蕴含在约定和技巧之中。
本书的方法
假定读者有C++基本语法的背景,本书试图把精通C++的专家们所获得的语言的风格和习惯用法传授给读者。本书展示了如何把C++语言的不同风格用于简单的数据抽象、“羽毛丰满”的抽象数据类型的实现以及面向对象程序设计。与此同时,本书也探索新的、C++语言间接支持的核心习惯用法,诸如基本功能和框架的程序设计以及高级垃圾收集技术。
本书的结构
本书用围绕语言的特征来学习C++高级特征。从支持C++特征的观点出发,来考虑C++特征中不断增长的强有力的抽象。本书每个章节都围绕习惯用法的家庭来组织,习惯用法渐进地建立在相互之间有关联的后继各章中。
第1章提供了C++习惯用法的历史背景。该章提供了一些产生习惯用法的原动力以及能够作为C++语言一部分或作为语言外部使用的不同的习惯用法。
第2章介绍了基本的C++语言构造块:类和成员函数。虽然很多素材是基本的,但本章建立的习惯用法和公用程序在后面章节中会再次出现。从设计观点出发,本章还介绍了编译类型系统和用户定义类型与类之间的关系,同时也介绍了const的更有用的习惯用法。
第3章介绍了使用类的“完全”类型的习惯用法。C++已经自动演变成许多拷贝工作和初始化对象工作,但对大多数类来说,程序员仍然需要定制赋值和默认的构造函数。本章提供了定制的框架,描述了调用的规范格式即定义了在对象工作机制下的原则和标准。除了大多数共同使用的规范格式以外,还将习惯用法引入到对新的和已有的类的引用计数之中。本书最初的习惯用法超出了直截了当地应用基本的C++语法的范畴,在引用计数、计数指针上的变化方面导致了从C++中把计算机的灵巧的指针、类似于对象的指针舍去。最后,本章还寻找如何把对象的建立从初始化中分离出来,这对熟悉基本C++的程序员来说,似乎是个不太自然的习惯用法:C++与紧密地耦合出现的两种操作相关联,在方法设计的驱动中以及在相互依赖资源的系统中需要分离它们的出现。
第4章介绍继承。
第5章添加了介绍面向对象程序设计继承的多态性。许多新的C++程序员正在变成“继承热”,在各种场合中都使用它。继承的确是大多数面向对象范型所支持的重要特性,它对软件可重性应用特别有用。第5章还介绍了继承与多态性的区别,以帮助读者识别这两种概念从而避免出现混淆。
第6章从结构和设计的剖面介绍C++的构造方法、风格和习惯用法。考察类在应用层面上的含义以及在高层语法上的含义。正确评价应用和抽象设计之间的关系,正确评价实现的类和对象之间的关系,以促进系统的健壮性并易于演化。另一个关键的进展是超越了具体应用的拓宽设计,覆盖了整个领域的应用。对这个领域分析的指导原则是本章的重要部分。本章还包含了适合继承使用的经验作法以及对不熟悉C++语言的程序员的难点领域等许多经验作法。经历过面向对象设计考验的读者将懂得如何把设计的输出转化为C++代码,作为继承替代物的封装性是C++语言上下文中的研究对象,可重用和多态性也是其研究对象。
第7章研究代码和设计的可重用性,介绍4种不同的代码机制,特别值得关注的是“继承热”的优缺点。本章介绍了使用模板的参数化类库的一些习惯用法,以便减少代码生成量。
本书剩下的部分超出了C++本身的范畴,进入到高级程序设计的习惯用法。
. 第8章介绍样本实例,以取代C++类的许多重要角色。这些例子作为特殊对象来介绍,以解决某些共同的开发问题,诸如“虚拟构造方法”问题,而这些例子也给支持类独立性和开发独立性的更强有力的设计技术奠定了基础。
第9章集中在符号语言风格上,打破了许多C++程序设计所保持的基本概念,包括强类型和显式内存管理。本章的习惯用法的确超越了C++开发的主流范畴,是在Smalltalk和Lisp中发现并保留下来的风格。
第9章还介绍了支持增量式运行时更新的习惯用法。这种习惯用法的实现必须依赖于目标平台的许多细节。该材料的要点是使读者精通增量式装入问题必须工作的技术层面,这个例子是典型的。作为技术的进展,第9章的目的不是把C++改造成Smalltalk,这是不可能的,也是不应当的。这些习惯用法缺少对编译时间类型的安全检查,通常比“本机C++”代码效率要低一些。所以,这些习惯用法一定要提供一定的灵活性和自动内存管理的增量式手段。
第10章覆盖了动态多重继承。多重继承是C++有争论的特征。这种动态变化的讨论应避免传播到其他章节,而静态多重继承在第5章作为值来描述。动态多重继承避免了类组合的组合爆炸问题。我们已经发现这种方法在许多真实生活问题中是有价值的,它包含在编辑器、CAD系统和数据库管理系统之中。
第11章讨论高层对象的系统性问题。本章产生C++类的大板块以上的抽象层次,包括大型或特大型的软件构造、组织和管理。本章还将讨论大量的重要的系统性问题,包括调度、例外处理、分布式处理,还将讨论模块化和可重用的指南。本章把第6章和第7章紧密地联系在一起,在这些讨论之中也包含了对库结构和维护方面的考虑。
在附录A中,把基本C++概念与C语言进行比较,许多读者已经学习过这些基本的或者能够找到介绍这些基本概念的文本。在这里包含这些材料有两个理由。第一,作为一种参考,当你需要澄清某些糊涂概念和结构时,不需要去费劲地寻找这样的文本。第二,C和C++风格是一种设计观点,表示如何融合过程和面向对象代码。这对C++程序员的基本C代码的工作非常重要。
本书的例子虽然是基于C++3.0标准版本的,但对于目前许多其他平台以及其他一些C++环境也很适用,对于C++高版本显而易见是适用的。书中的实例基于通用目的,读者可以通过本书的例子举一反三,稍加修改即可应用到具体项目之中,或作为设计的框架,或作为完整的主体,许多通用的类都可以在本书中找到。
感谢
本书的出版都归功于我的朋友。首先,原动力来自于贝尔实验室Chris Carson的启示,无疑他是这本书的倡导老师,我感谢他主动积极的支持。本书还与Keith Wollman的指导,我的阅历丰富的编辑以及其负责的管理主任Helen Wythe有关。Lorraine Mingacci与我,对第6章进行了深刻又有意义的争论,并且我还与她对本书其余部分进行了详细讨论。本书还要归功于治学作风严谨的核心小组的多次讨论,他们贡献了许多有益的概念,这个核心小组成员有:TimBom,Margaret A. Ellis,Bill Hopkins,Andrew Koenig,Start Lippman,Barbara Moo,Bonnie Prokopowicz,Larry Schutte和Bjarne Stroustnp。Alexis Layton,Jim Adcock和Mike Ackroyd提出了许多好的建议,使本书更加精彩,我深深地感谢他们。还有许多其他的贡献要归功于Miron Abramovici,Martin Carroll,Brian Kernighan,Andrew Klein,DougMcllroy,DennisMancl,Warren Montgomery,Tom Mueller,Anil Pal,Peggy Quinn和Ben Rovegno。幸亏借助于Mary Crabb,Jean Owen和Chris Scussel在文本格式上出色的经验以及Brett L.Schucher和Steve Vinoski辛勤的工作,得以在早期就发现了一些打印的错误:正是由于他们的努力,改善了打印的质量,最终避免了照相排版文档的缺陷。在确定具体章节标题上真的要特别感谢Judy Marxhansen。
本书的出版不能忘记AT&T经理们的支持,是他们给了我充足的时间和资源。谢谢Panl Zislis和BenRovegno最宝贵的支持,并特别感谢Warren Montgomery,Jack Wang和Eric Sumner,Jr.从道义上思想上的支持。
我还要说明的是从上我课的许多学生那里也汲取了许多好的营养,并反映到本书之中。特别感谢在1989年Naperville,Illinois和Columbus,Ohio以及AT&T贝尔实验室中我所教过的C++课程的学生们。