通过对本套教材第 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网站上找到该系统。非常感谢您的帮助。
关于封面
封面上的艺术作品由 Larry O誃rien的妻子Tina Jensen绘制(是的,就是那个在《软件开发》杂志中任多年编辑的Larry O誃rien)。封面不但图画很美,而且也很好地体现了多态性。采用这些图画的灵感来源于Daniel Will-Harris,他是一位封面设计者(www.Will-Harris.com),Bruce 的同事。
致谢
本教材的第 2卷曾长时间停留在完成一半的状态,这是因为Bruce还要去做其他事情,即忙于Java、设计模式,尤其是Python (详见www.Python.org)等方面的工作。如果Chuck那时没有心甘情愿地(Chuck 有时认为自己当时的做法很愚蠢)去完成本书的另一半工作,这本教材几乎就不会问世。他是Bruce愿把这份未完的工作托付给的极少数人之一。Chuck 做什么事都追求精确无误,他清晰的解释促成了本教材今天的辉煌。
Jamie King是在本教材完成过程中由Chuck指导的实习生。他是保证这本教材顺利完成必不可少的一分子;他不但为Chuck提供反馈信息,更可贵的是他不懈地发现与置疑他不完全理解的教材中的每一个细节。如果本教材回答了读者的问题,那么很可能就是因为Jamie先问过这个问题了。Jamie还改进了许多示例程序并在每一章的末尾设计了很多练习题。Chuck的另一位由MindView公司资助的实习生Scott Baker帮助完成了第3章的练习题。
IBM的Eric Crahen在第11章(并发)的完成过程中发挥了很大作用。在寻找合适的线程软件包时,我们找到了一个直观、易用的软件包,而且该软件包在完成工作的过程中体现了足够的健壮性。我们从Eric那里得到了这个软件包以及其他一些帮助—他非常乐于合作,而且他还根据使用中的反馈意见来增强他的类库,我们也从他的见解中获益很多。
非常感谢 Pete Becker担任本教材的技术编辑。极少有人能像Pete那样出众而且善于表达自己的想法。像Pete那样能够精通C++和软件开发的人也不多。我们也非常感谢Bjorn Karlsson的慷慨和他及时的技术支持,因为他审阅了整个文稿,并做了精辟的批注。
Walter Bright为确保他的Digital Mars C++编译器可以编译教材中的所有实例,曾做过不懈的努力。他还将其编译器作为http://www.DigitalMars.com上可免费下载的软件。谢谢了,Walter!
本教材中的思想和见解来源于许多方面。包括:我们的朋友们,如 Andrea Provaglio、Dan Saks、Scott Meyers、 Charles Petzold和Michael Wilk;语言开拓者,如Bjarne Stroustrup、Andrew Koenig和Rob Murray;C++标准委员会成员,如Nathan Myers(他给我们提供了特别的帮助和毫无保留的见解)、Herb Sutter、PJ Plauger、 Kevlin Henney、David Abrahams、Tom Plum、Reg Charney、Tom Penello、Sam Druker、Uwe Steinmueller、John Spicer、Steve Adamczyk和Daveed Vandevoorde;在软件开发会议上就C++领域发展进程发过言的人员(该会议由Bruce创建和促进,Chuck在会上发表演说);Michael Seaver、Huston Franklin、David Wagstaff等Chuck 的同事;还有培训班上的学生们,我们需要认真听取他们的问题从而使这本教材更加清晰易懂。
本教材的规划、字体的选择、封面设计以及封面照片由 Bruce的朋友Daniel Will-Harris来完成,他是著名作家和设计师。他在初中时就常常研究字母,那时就期待着计算机的发明和桌面排版系统的问世。此外,我们自己做了排版文件,所以排版错误是我们的错误。本教材是使用Microsoft* Word XP来编写的。排版文件也是使用该软件生成的。正文的字体选用Georgia,标题采用的是Verdana,代码采用的字体是Andale Mono(以上指本书英文版)。
在这里也感谢 Edison Design Group和Dinkumware有限公司慷慨的专业技术人员,感谢他们让我们免费拷贝了他们的编译器和类库(分别拷贝的)。没有他们的专业帮助及无私的给予,本教材中的一些程序示例根本无法得到调试。还要感谢Howard Hinnant和Metrowerks的工作人员,感谢让我们拷贝他们的编译器;还要感谢Sandy Smith和SlickEdit的人员,正是他们这么多年来一直为Chuck提供世界一流的编写环境。此外,Greg Comeau也贡献出了他的基于EDG的编译器的拷贝(Comeau C++),这里一并表示感谢。
特别要感谢我们的所有老师及所有学生(他们也是我们的老师)。
Evan Cofsky(Evan@TheUnixMan.com) 提供了服务器方面的多种帮助。他也曾用其擅长的语言—Python,在程序研发工作中为本教材尽心尽力。Sharlynn Cobaugh 和Paula Steuer 也帮了不少忙,他们的帮助使Bruce 能够从繁忙的项目中脱身出来。
Bruce 的妻子 Dawn McGee 在本教材编写期间给予了很多灵感和巨大热情。以下是对本教材的出版给予过支持的朋友们的部分名单,但不是全部: Mark Western 、 Gen Kiyooka 、 Kraig Brockschmidt 、 Zack Urlocker 、 Andrew Binstock 、 Neil Rubenking 、 Steve Sinofsky 、 JD Hildebrandt 、 Brian McElhinney 、 Brinkley Barr 、 Midnight Engineering 杂志的 Bill Gates 、 Larry Constantine 和 Lucy Lockwood 、 Tom Keffer 、 Greg Perry 、 Dan Putterman 、 Christi Westphal 、 Gene Wang 、 Dave Mayer 、 David Intersimone 、 Claire Sawyers 、几位意大利籍朋友( Andrea Provaglio 、 Laura Fallai 、 Marco Cantu 、 Corrado 、 Ilsa 和 Christina Giustozzi )、 Chris 和 Laura Strand 、 Almquist 一家、 Brad Jerbic, John Kruth & Marilyn Cvitanic, Holly Payne (就是那个著名的小说家!)、 Mark Mabry 、 Robbins 一家、 Moelter 一家(还有 McMillan 一家)、 Wilk 一家、 Dave stoner 、 Laurie Adams 、 Cranston 一家、 Larry Fogg 、 Mike 和 Karen Sequeira 、 Gary Entsminger 和 Allison Brody 、 Chester Andersen 、 Joe Lordi 、 Dave 和 Brenda Bartlett 、 Rentschler 一家、 Sudek 一家、 Lynn 和 Todd ,还有他们的家人。当然,还有我们的父母、 Sandy 、 James 和 Natalie 、 Kim 和 Jared 、 Isaac 和 Abbi 。