前言

通过对本套教材第1卷的学习,读者已经掌握了C与C++的基础知识。这一卷将涉及其更为高级的特性,使读者领悟C++编程的方法与思想,从而编写出健壮的C++程序。

现在假定读者已经熟悉了第1卷的内容。

目标

编写这套教材的目标是:

1.每节只介绍适当的学习内容,使学习向前推进一小步。因此读者能很容易地在继续下一步学习前消化每个已学过的概念。

2.讲授实用编程技巧,以便读者在日常的学习和工作中使用这些技巧。

3.只把对于理解这门语言比较重要的内容介绍给读者,而不是将我们所知的一切都罗列出来。我们相信,不同信息的重要性是不同的。有些内容对于95%的程序员来说肯定没有必要知道,这些信息只会迷惑人们,加深人们对这门语言复杂性的恐惧。举一个关于C语言的例子,如果记住运算符优先级表(我们从未做到这一点),就能够写出漂亮的代码。但如果对其进行深究,它会让代码的读者或维护者感到迷茫。所以可以摒弃优先级,而在优先级不很清楚的情况下使用括号。同样,C++语言中的某些信息对于写编译程序的人员来说更为重要,而对程序员来说却没那么重要。

4.尽可能将每一节内容充分集中,使得授课时间及两个练习之间的间隔时间不长。这样不仅能使读者的思维在每次课堂研讨会期间更加活跃与投入,还可使他们有更大的成就感。

5.尽力不用任何特定厂商的C++版本。我们已在所有能见到的C++实现版本中测试了本教材中的代码(前言中稍后将有介绍),有的实现版本无法工作,那是因为它没有遵循C++标准,我们已经在示例中标注这些事实(读者会在源代码中看到这些标注),以便将其从构建过程中摒弃。

6.教材中代码的自动编译和测试。由于已经发现未经编译和测试的代码很可能有问题,所以在这一卷中,本教材所提供的例子全是测试过的代码。此外,读者可从http://www.MindView.net下载这些代码,它们是直接从本教材的文本中摘录的,这些程序能够用自动生成的测试文件进行编译和运行测试。读者可以通过这种方式知道教材中的代码都是正确的。

各章简介

下面是本教材各章内容的简要介绍。

第一部分 建立稳定的系统

第1章 异常处理。出错处理在程序设计中一直是一个问题。即便你返回了错误信息或设置了一个标志,函数调用者还会对此视而不见。异常处理是C++的主要特征之一,该机制解决这类问题的方法如下:在致命错误发生时,允许该函数“抛出”一个对象。对应于不同的错误抛掷不同类型的对象,那么该函数的调用者就可以在独立的出错处理子程序中“捕获”这些对象。如果程序中抛出了一个异常,该异常就不能被忽略,这样就可以保证会触发一些事件来响应这一错误。决定采用异常处理机制是影响代码设计向良性方向发展的重要方法。

第2章 防御性编程。许多软件故障都是可以预防的。防御性编程是一种编写代码的方式,采用此种方式能够较早地发现并更正错误,从而避免了这些错误对相关工作区域造成的危害。在开发过程中使用断言(assertion)是一种很重要的方法,该方法能够在程序员编写代码的过程中进行合法性检验,与此同时在代码中留下了一个可执行文档,该文档可用来揭示程序员开始编写代码时的思路。在向用户交出程序前应严格地测试编写的代码。对于成功地进行常规软件开发的人员来说,自动单元测试框架是一个不可缺少的工具。

第二部分 标准C++库

第3章 深入理解字符串。最为常见的编程工作是对文本进行处理。C++字符串类将程序员从内存管理事务中解脱出来,使其有足够的时间和精力增强文本处理能力。此外,为适应国际化应用的需求,C++也支持对宽字符和区域字符的操作。

第4章 输入输出流。输入输出流类是最早的C++库之一,它提供必不可少的输入输出功能。使用输入输出流类就是用I/O库来代替C语言中的stdio.h。这种I/O库用起来更容易、更灵活并且更易于扩展—可对其做适当的调整使之能够与新定义的类一起工作。该章告诉读者怎样充分利用现有的输入输出流类库来实现标准I/O、文件I/O以及内存中的格式化操作。

第5章 深入理解模板。现代C++的显著特征是模板的强大功能。模板的作用不仅仅在于生成容器。借助于模板,还可开发出具有健壮性、通用性和高性能的类库。关于模板的内容,需要了解的还有很多,它们构成了C++语言内的一个子语言,使得程序员能在更大程度上控制编译过程。模板的引入对C++程序设计来说是一场革命,可以毫不夸张地说,自从有了模板,C++程序设计焕然一新了。

第6章 通用算法。算法处于计算的核心。C++借助其模板功能提供了一大批功能强大、高效且易用的通用算法。标准算法也可以通过函数对象进行自定义。该章研究了模板库中的所有算法。(第6章和第7章讲的是标准C++模板库,也就是通常所说的标准模板库(Standard Template Library, STL)。)

第7章 通用容器。C++以一种类型安全的方式提供对所有常见数据结构的支持。用户不必为容器中的内容而感到忧虑,其对象的同一性得到了保证。可通过迭代器将容器的遍历与容器自身相分离,这是模板的又一杰作。这种巧妙的安排能够将算法灵活应用于容器,而容器则采用了最简单的设计。

第三部分 专题

第8章 运行时类型识别。当你只用一个对象指针或引用指向基类型时,运行时类型识别(Runtime_type Identification, RTTI)就会找到该对象的确切类型。一般情况下,有时会有意忽略掉一个对象的确切类型,而利用虚函数机制实现对应于那个类型的正确操作。但有时(比如当编写像调试器这样的软件工具时)借助于此信息知道一个对象的确切类型是非常有用的,常常可以非常有效地进行某些特殊操作。这一章解释RTTI的用途及其使用方法。

第9章 多重继承。一个新类可以从多个现存类中继承,这话乍听起来很简单。但是,由此而产生的二义性和对基类对象的多次复制将很难避免。这些问题可通过建立虚基类来解决,但更大的问题仍然存在:什么时候用多重继承?只有当你需要通过多于一个的公共基类来操作一个对象时,多重继承才是必需的。这一章对多重继承的语法做了解释,也提出了可选方案—特别针对使用模板怎样解决一个典型问题进行了深入讨论。运用多重继承来修复一个“被损坏了的”类接口是关于C++这一特性的经典案例。

第10章 设计模式。自从对象产生以来,在程序设计领域最具革命性的飞跃是设计模式的引进。设计模式是对应于公认的编程问题的经典解决方案,它独立于语言之外,其表述方式的特殊性使它能应用于许多情况之下。因此,像单件(Singleton)、工厂方法(Factory Method)和访问者(Visitor)这样的模式现都已被一般的程序员接受和使用了。这一章介绍如何通过C++来实现和使用一些较为有用的设计模式。

第11章 并发。人们越来越期待有响应功能的用户接口,而这种接口能(看起来像)同时处理多任务。现代操作系统允许进程拥有共享进程地址空间的多线程。多线程程序设计要求编程人员有与众不同的思维方式,然而,在进行多线程程序设计时也会遇到一些困难。这一章通过一个可免费获得的类库(由IBM的Eric Crahen提供的ZThread库)介绍怎样使用C++来有效地管理多线程应用。

练习

我们发现,在课堂讨论期间使用简单的练习特别有助于学生对相关概念的理解。所以,在每一章后面都附有一定量的练习题。

这些练习题十分简单,可当堂完成;但有一点,需要有老师在场观察证实,以确保所有的学生都掌握了相关内容。有些练习题有一定的挑战性,是为激发优秀学生的学习兴趣准备的。所有练习被设计为可以在短时间内完成,只是用来测试和完善学生所掌握的知识,而不是为了提出挑战(很可能读者自己会找到这些难题—或者更可能的是难题会自己找上门来)。

源代码

本教材的源代码是免费版权软件,通过网站http://www.MindView.net发布。该版权是为了防止在未经许可的情况下在印刷媒体上再度出版这些代码。

只要遵守代码中的版权声明,读者就可以在自己的项目里和课堂上使用这些代码。

编译器

读者使用的编译器可能不支持本教材所论及的C++的所有特征,尤其是当该编译器并非是其最新版本的时候,这种情况就显得尤为突出。所以实现像C++这样的语言绝非易事;同时读者会希望C++的特征一点点展现,而非一下子全部出现。但是,如果读者试做了教材中的一个例子,结果编译器报告了一大堆错误,这就不一定仅仅是代码或编译器中的一个故障那么简单了—很可能在读者选用的编译器上根本就运行不了那个代码。

教材中的代码已经用很多编译器进行过测试,目的是确保这些代码符合C++标准,并且在尽可能多的编译器上运行。遗憾的是,并非所有的编译器都符合C++标准,因此在使用这些编译器构造可执行文件时,去掉了某些文件。这些被去除的文件在makefiles里都有体现,而makefiles是为这本教材的代码包自动生成的,并且可从http://www.MindView.net下载。在makefiles中,从每个程序代码清单开头的注释中都可以看到这些嵌入的排除标记符,这样读者将会知道是否应让某个特定的编译器来运行那个代码(少数情况下,编译器确实会编译代码,但执行动作却是错的,本教材将这些代码也排除在外)。

下面就是有关的排除标记符和相应的编译器:

·{-dmc}Walter Bright的Digital Mars编译器,专为Windows设计,可从www.DigitalMars.com免费下载。这种编译器兼容性超强,整本教材中几乎都看不到该排除标记符。

·{-g++}免费的Gnu C++3.3.1,在大多数Linux软件包和Macintosh OSX中都预装了该编译器。该编译器也是专为Windows设计的Cygwin的一部分(见下文)。从gcc.gnu.org可以得到其为其他大多数操作平台而设计的版本。

·{-msc}Visual C++. NET是微软(Microsoft)推出的第7版编译器(使用前必须先安装Visual Studio.NET,不能免费下载)。

·{-bor}Borland C++第6版(不可免费下载;这是最新的版本)。

·{-edg}Edison Design Group(EDG)C++。该编译器可用来检测代码是否符合标准C++。只是由于类库的原因才出现了这个标记符,因为本教材采用了Dinkumware有限公司赠送的带有兼容类库的EDG前端免费副本。单独使用编译器不会出现任何编译错误。

·{-mwcc}为Macintosh OSX设计的Metrowerks Code Warrior。注意,使用OSX也必须先安装Gnu C++编译器。

如果从http://www.MindView.net下载并解压了本教材的代码包,读者会发现用来为上述编译器建立代码的构造文件(makefiles)。本教材使用免费的GNU-make,它在Linux、Cygwin(一个可在Windows上运行的免费Unix shell,详见www.Cygwin.com)环境下运行,也可安装在读者自己的计算机平台上—详见www.gnu.org/software/make。(这些文件在其他make上也可能运行,但得不到支持。)一旦安装了make,如果在命令行运行方式下键入make,就会得到有关如何为上述编译器建立教材中代码的操作步骤。

注意,本教材程序示例文件中的这些标记符指出了当时调试用的编译器的版本。很可能在这本教材出版后相应的编译器版本已经升级。也有可能我们在使用很多编译器对本教材中的代码进行编译时,错误地配置了某个编译器;如果没有配错编译器,则相应的代码应该早已经被正确地编译。因此,在自己的编译器上重新调试这些代码,并检查从http://www.MindView.net网站下载的代码是否为最新版本就显得尤为重要。

语言标准

在本教材中,当提到ANSI/ISO C标准时,指的是1989标准,而且一般情况下只是说“C”。只有当有必要区分标准1989 C和较早的版本,如制定标准前的C语言版本时,才会做出区分。在本教材中并不涉及C99。

ANSI/ISO C++委员会很早以前就制定出了第一个C++标准,通常称为C++98。本教材用“标准C++”来指这个标准化语言。如果只说C++,那就意味着是“标准C++”。C++标准委员会还在继续发布对使用C++的公众群体很重要的信息,这些会促使另一C++标准C++Ox的形成,但它的产生在近几年内不太可能实现。

研讨班和咨询

Bruce Eckel的公司—MindView公司,提供基于本教材中的材料和高级主题的公共实习培训研讨班。每课所讲的都是从各章中精选的内容,每次讲授完毕,后面有一个检测练习阶段,每个学生都能够受到个别指导。我们还提供现场培训、咨询、辅导、设计和代码演练的服务。从http://www.MindView.net网站上可获得有关即将开办的研讨班信息、相关报名表和其他联系信息。

错误

无论我们怎样挖空心思地去检查错误,总会漏掉一些错误,但这些错误却常常能被热心的读者发现。如果读者发现了任何认为是错误的地方,请使用本教材电子版中的反馈系统与我们联系。读者可在http://www.MindView.net网站上找到该系统。非常感谢您的帮助。