C++编程思想(第2版) 第1卷:标准C++导引
作者 : Bruce Eckel
译者 : 刘宗田 袁兆山 潘秋菱 等
丛书名 : 计算机科学丛书
出版日期 : 2002-09-01
ISBN : 7-111-10807-8
定价 : 59.00元
教辅资源下载
扩展信息
语种 : 简体中文
页数 : 516
开本 : 16开
原书名 : Thinking in C++, Vol.1: Introduction to Standard C++
原出版社: Prentice Hall
属性分类: 教材
包含CD :
绝版 :
图书简介

本书第1版荣获美国“软件开发”杂志评选的1996年图书震撼大奖(Jolt Award),中文版自2000年推出以来,经久不衰,获得了读者的充分肯定和高度评价。
  第2版与第1版相比,在章节安排上有以下改变。增加了两章:“对象的创建与使用”和“C++中的C”。前者与“对象导言”实际上是第1版“对象的演化”一章的彻底重写,增加了近几年面向对象方法和编程方法的最新研究与实践的丰硕成果;后者的添加使不熟悉C的读者可以直接使用本书。删去了四章:“输入输出流介绍”、“多重继承”、“异常处理”和“运行时类型识别”,删去的内容均为C++中较复杂的主题,作者将它们连同C++标准完成后增加的一些内容放到本书的第2卷中,使本书的第1卷内容显得更加集中,可以供不同程度的读者选择阅读。需要强调的是,第2版的改变不仅体现在这些章节的调整上,更多的改变体现在每一章的字里行间,包括例子的调整和练习的补充。与众不同的精心选材和认真推敲的叙述使得第2版更趋成熟。
  本书是C++领域内一本权威的著作,书中的内容、讲授方法、例子和练习既适合课堂教学,又适合读者自学。无论是高等院校计算机及相关专业的学生,还是业界的从业人员,以及广大的计算机爱好者,都可从阅读本书中获益。

图书前言

像任何人类语言一样,C++提供了一种表达思想的方法。如果这种表达方法是成功的,那么当问题变得更大和更复杂时,该方法将会明显地表现出比其他方法更容易和更灵活的优点。
  不能只把C++看做是语言要素的一个集合,因为有些要素单独使用是没有意义的。如果我们不只是用C++语言编写代码,而是用它思考“设计”问题,那么必须综合使用这些要素。而且,为了以这种方法理解C++,我们必须了解使用C的问题和一般的编程问题。本书讨论的是编程问题、为什么这些编程问题会成为要解决的问题以及用C++解决编程问题所采用的方法。因此,在每一章中所解释的一组语言要素,都建立在C++语言解决某一类特殊问题所用方法的基础之上。以这种方式,我希望一点一点地引导读者,从掌握C开始,直到读者使用C++变成自己的母语思维方式。
  我将始终坚持一种观点:读者应当在头脑中建立一个模型,以便逐步理解这种语言,直到炉火纯青的程度。如果读者遇到难题,他可以将问题纳入这个模型,推导出答案。我将努力把已经印在我脑海中的见解传授给读者,正是这些见解,使得我能开始“用C++进行思考”。

0.1  第2版中的新内容
  本书是第1版的彻底重写,反映了C++标准最终完成所带来的C++的所有改变,也反映了自从第1版写完后我又学习到的内容。我已经检查并重写了第1版中的全部文字,在这个过程中,我删去了一些过时的例子,修改了一些现有的例子,并增加了一些新的例子和新的练习。我对第1版的内容进行了大规模的重新整理和重新编排,以便反映新出现的更好的工具和我对人们如何学习C++的进一步理解。为方便没有C背景知识的读者能阅读本书后面的章节,在第2版增加了一章,简要地介绍C概念和基本的C++特征。本书配套的CD ROM包含了一份课堂讨论的材料,这是为了理解C++(或Java)所必需的C概念的介绍,这是由Chuck Allison为我的公司(MindView, Inc.)创建的,称为“Thinking in C: Foundations for Java and C++”,它介绍了转向C++或Java所必需的C的知识。其中省略了C程序员必须每天面对,而C++和Java语言能让我们避免的繁琐的内容(在Java中,甚至可能消除这些繁琐的工作)。
  因而,对于“第2版与第1版相比有何不同”这个问题的简要回答是:不同之处不在于版本号是新的,而是进行了重写,有的地方读者甚至无法认出原来的例子和材料。
  0.1.1  第2卷的内容是什么
  C++标准增加了一些重要的新库,例如String、在标准C++库中的容器和算法,以及模板中的新的复杂性。这些新增的内容和其他更高级的主题被放进本书的第2卷,包括多重继承、异常处理、设计模式和建立和调试稳定系统等内容。
  0.1.2  如何得到第2卷
  就像当前你手上的这本书一样,《C++编程思想》第2卷完全可以从我的网站www.BruceEckel.com上下载。
  这个站点还包括这两本书的源代码,以及有关MindView公司提供的CD ROM上其他课堂讨论材料的更新和信息,其中包括:公开课堂讨论、内部培训、辅导课和演示。

0.2  预备知识
  在本书第1版中,我假定读者已经学习了C,并至少具有自如阅读的水平。我的重点放在简化我认为比较困难的部分:C++语言。第2版增加了一章,快速地介绍C,并在光盘上提供“Thinking in C”的课堂讨论材料,但是即使如此,我仍然假设读者具有一定的程序设计经验。另外,正如读者可以通过读小说而直接地学会许多新词一样,读者也可以从在本书后面的文字中学习有关于C的大量知识。

0.3  学习C++
  我希望本书的读者有和我进入C++时相同的情况:作为一个C程序员,对于编程持有实在而执着的态度。但糟糕的是,我的背景和经验是在硬件层的嵌入式编程方面。在那里,C常常被看做高层语言,它对于位操作是低效率的。后来我发现,自己甚至不是一个好的C程序员,平时总是掩盖了对malloc( )和free( )、setjmp( )和longjmp( )结构以及其他“复杂”概念的无知,当开始触及这些主题时就竭力回避,而不是努力去获取新的知识。
在我开始致力于学习C++时,当时惟一像样的书是Stroustrup夫子自道式的“专家指南”,因此我只好靠自己弄清基本概念。这引出了我的第一本关于C++的书,这本书基本上就是直接把我头脑中的经验倒出来而写成的。它的构思是作为读者的指南,引导程序员同时进入C和C++。这本书的两个版本 都收到了读者的热情反响。
  几乎就在《Using C++》出版的同时,我开始讲授这门语言。讲授C++已经变成了我的职业。自1989年以来,在授课时我看到了世界各地听众昏昏欲睡的样子、茫然不知的面容和困惑不解的表情。当我对一些人数不多的人群进行内部培训时,在练习过程中又发现了某些问题。即便那些面带微笑和会心点头的学生,实际上对许多问题也还是糊涂的。通过开创和多年主持“软件开发会议”的C++和Java系列专题,我发现,我和其他讲演者都有一种倾向,即过快地向听众灌输了过多的主题。后来,我做了一些努力,通过区别对待不同层次的听众和提供相关资料的方法,尽量吸引听众。也许这是过分的要求,但是因为我是一个抵触传统教学的人(对于大部分人而言,我相信这种抵触源于厌倦),所以希望我通过努力,使每一个人都能跟得上教学进度。
  有一段时间,我编写了大量的教学演示。这样,我结束了通过实验和重复方式进行学习(在设计C++程序的过程中,这也是一项很有用的技术)的阶段。最后,从我多年的教学经验中总结出来的所有内容,形成了一门课程。在课程中,我用一系列分离的、易于理解的步骤并采用实地课堂讨论的形式解决学习中的问题(理想的学习情况),并在每次课后面跟随着练习。读者能从www.BruceEckel.com找到我的公开课堂讨论,还可以学习我已经制作成CD ROM的课堂讨论材料。
  本书的第1版是作为两学年制课程编写的,并且书中的内容已经在许多不同的课堂讨论上通过了多种形式的检验。我从每次课堂讨论上收集反馈意见,不断地修改和调整内容,直到我感觉到它已经成为一本很好的教材为止。但这本书不仅仅是课堂讨论的分发教材,而且我在其中放入了尽可能多的信息,在结构上使得它能引导读者顺利地通过当前主题和进入下一个主题。另外,这本书也适合于自学读者,能帮助他们尽快地掌握这门新的编程语言。

0.4  目标
  在这本书中,我的目标是:
  1) 以适当的进度介绍内容。每次将学习向前推进一小步,因此读者能很容易地在继续下一步学习之前消化每个已学过的概念。
  2) 尽可能使用简短的例子。当然,这有时会妨碍我解决“现实世界”的问题。但是,我发现,当初学者能够掌握例子的每个细节,而不受问题的领域所影响时,他们通常会更有兴趣进行学习。另外,在课堂情况下能达到的接受能力,对代码的长短也有严格的限制。为此,我有时会受到使用“玩具例子”的批评,但是我甘愿承受这一批评,因为这样更有利于取得某些教学法上的效果。
  3) 仔细安排描述内容的顺序,不让读者看到还没有揭示的内容。当然,这不是总能做到的;如果出现了这种情况,我将会给出简明的介绍性的描述。
  4) 只把对于理解这门语言比较重要的东西介绍给读者,而不是介绍我知道的所有内容。我相信,不同信息的重要性是不同的。有些内容是95%的程序员不需要知道的,这些东西只会迷惑人们,增加他们对该语言复杂性的感觉。举一个C语言的例子,如果我们记住运算符优先表(我是记不住的),我们就可以写更漂亮的代码。但是,如果一定要这样做,反而会使代码的读者或维护者糊涂。所以可以忘掉优先级,当不清楚时使用括号。我们对于C++中的某些内容也可以采取同样的态度,因为我认为这些内容对于写编译器的人更重要,而对于程序员就不是那么重要。
  5) 保持每一节的内容充分集中,使得授课时间以及两个练习之间的间隔时间不长。这不仅能使听众保持活跃的思想和在课堂讨论中精力集中,而且会使他们有更大的成就感。
  6) 帮助读者打下坚实的基础,使得他们能充分地理解面对的问题,从而可以顺利地转向学习更困难的课程和书籍(特别是这本书的第2卷)。
  7) 我尽力不用任何特定厂商的C++版本,因为对于学习编程语言,我不认为特定实现的细节像语言本身一样重要。大部分厂商的文档只适合于他们自己的特定实现。

0.5  各章概要
  C++是一个在已有文法上面增加了新的不同特征的语言(因此,它被认为是混合的面向对象的编程语言)。由于很多人走了学习弯路,因此我们已经开始探索C程序员转移到C++语言特征的方法。因为这是过程型训练思想的自然延伸,所以我决定去理解和重复相同的道路,并通过引出和回答一些问题来加速这一进程,这些问题是当我学习该语言时遇到的和听众在听我的课时提出来的。
  设计这门课时,我始终注意一件事:精练C++语言的学习过程。听众的反馈意见帮助我认识到哪些部分是很难学习的和需要额外解释的。在这个领域中,我曾经雄心勃勃,一次讲解包括了太多的内容。通过讲解过程,我知道了,如果包括大量新特征,就必须对它们全部作出解释,而且学生也特别容易混淆这些新特征。因此,我努力一次只介绍尽可能少的特征,理想的情况是每章一次只介绍一个主要概念。
  本书的目标是只在每一章中讲授一个概念,或只讲授一小组相关的概念,用这种方法,不会依赖于其他的特征。这样,在进入下一章的学习之前,学生可以对自己的当前知识融会贯通。为了实现这个目标,我把一些C特征留到后面的章节去介绍,甚至放在比我希望的还要往后的地方介绍。这样做的好处是读者不会因为看到了许多未解释的C++特征被使用而困惑,因此,对该语言的介绍将是和缓的,并且将反映出读者自己消化这些特征时将会采用的方式。
  下面是本书各章内容的简要说明。
  第1章  对象导言。当项目对于维护而言变得太大和太复杂时,就产生了“软件危机”。按程序员们的说法,“我们无法完成那些项目,即便能完成,它们也太昂贵了”。这引出了一些问题,在本章中我将讨论这些问题,并且讨论面向对象程序设计(OOP)的思想和如何运用这一思想解决软件危机问题。这一章引导读者了解OOP的基本概念和特征,介绍分析和设计过程。另外,在这一章中,我还将阐述采用这种语言的好处,提出关于如何转入C++语言领域的建议。
  第2章  对象的创建与使用。这一章解释用编译器和库建立程序的过程。它介绍了本书中的第一个C++程序,显示程序如何构造和编译,然后介绍标准C++中的可用对象的基本库。在结束这一章时,我们就对如何用流行的对象库编写C++程序有一个深刻的领会。
  第3章  C++中的C。这一章详细综述在C++中使用的C的特征和一些只在C++中使用的特征,还介绍在软件开发领域通用的“制作”工具,并且用它建立了本书中的所有例子(本书的源代码在www.BruceEckel.com中可找到,包含了对每章的makefile)。第3章假设读者已经具有某种过程型程序设计语言的坚实基础,例如Pascal和C语言或者甚至某种形式的Basic(只要读者已经用这种语言编写了大量的代码,特别是函数)。如果读者发现这一章有些难,就应当首先看本书附带的CD ROM上的“Thinking in C”的课堂讨论材料(亦可在www.BruceEckel.com下载)。
  第4章  数据抽象。C++的大部分特征都围绕着创建新数据类型的能力。这不仅可以提供优质代码组织,而且可以为更强大的OOP能力奠定基础。读者将可以看到如何用将函数放入结构内部的简单过程来实现这一思想,并可以看到如何具体地完成这样的过程和创建什么样的代码。读者还能学会组织代码成为头文件和实现文件的最好方法。
  第5章  隐藏实现。通过说明结构中的一些数据和函数是private(私有的),可以把它们设置为对于这个新结构类型的用户是不可见的。这意味着能够把下层实现和客户程序员看到的接口隔离开来,这样就容易改变具体实现,而不影响客户代码。另外,C++还引入关键字class作为描述新数据类型的更具吸引力的方法,而单词“对象”的意思并不神秘,它是一种美妙的变量。
  第6章  初始化与清除。C语言的最通常的一类错误是由于变量未初始化而引起的。C++的构造函数使得程序员能保证他的新数据类型(即“他的类的对象”)的变量总是能被恰当地初始化。如果他的对象还需要某种方式的清除,他可以保证这个清除动作总是由C++的析构函数来完成。
  第7章  函数重载与默认参数。C++可以帮助程序员建立大而复杂的项目。这时,可能会引进使用相同函数名的多个库,还可能会在同一个库中选择具有不同含义的相同的名字。C++采用函数重载使这一问题容易解决。重载允许当参数表不同时重用相同的函数名。默认参数通过自动为某些参数提供默认值,使我们能用不同的方式调用同一个函数。
  第8章  常量。本章讨论了const和volatile关键字,它们在C++中有另外的含义,特别是在类的内部。我们将学习对指针定义使用const的含义。本章还说明const的含义在类的内部和外部有何不同,以及如何在类的内部创建编译时常量。
  第9章  内联函数。预处理宏省去了函数调用开销,但是也排除了有价值的C++类型检查。内联函数具有预处理宏和实际函数调用的所有好处。这一章深入地研究了内联函数的实现和使用。
  第10章  名字控制。在程序设计中,创建名字是基本的活动,而当项目变大时,名字的数目是无法限制的。C++允许在名字创建、可视性、存储代换和连接方面有大量的控制。这一章将说明如何在C++中用两种技术控制名字。第一,用关键字static控制可视性和连接,研究它对于类的特殊含义。另一种在全局范围内更有用的控制名字的技术是C++的namespace(名字空间)特征,它允许把全局名字空间划分为不同的区域。
  第11章  引用和拷贝构造函数。C++指针的作用和C指针一样,而且具有更强的C++类型检查的好处。C++还提供了另外的处理地址的方法:继Algol和Pascal之后,C++使用了“引用”,允许当程序员使用平常的符号时由编译器来处理地址操作。读者还会遇到拷贝构造函数,它通过按值传送控制将对象传送给函数或从函数中返回的方式。最后,本章还将解释C++指向成员的指针。
  第12章  运算符重载。这个特征有时被称为“语法糖(syntactic suger)”。由于运算符也可以像函数调用那样使用,这使得程序员在运用类型的语法时更加灵活。在这一章中,读者将了解到,运算符重载只是不同类型的函数调用,并且将学会如何写自己的运算符重载,学会处理参数、类型返回以及确定一个运算符是成员还是友元时的一些易混淆的情况。
  第13章  动态对象创建。一个空中交通系统将处理多少架飞机?一个CAD系统将需要多少种造形?在一般的程序设计问题中,我们不可能知道程序运行所需要的对象的数量、生命期和类型。在这一章中,我们将学习C++的new和delete如何漂亮地通过在堆上安全地创建对象而解决上述问题。我们还将看到,new和delete如何用不同的方法重载,从而使我们能控制如何分配和释放存储。
  第14章  继承和组合。数据抽象允许程序员从零开始创建新的类型。通过组合和继承,程序员可以用已存在的类型创建新的类型。用组合方法,程序员可以以老的类型作为零件组装成新的类型;而用继承方法,程序员可以创建已存在类型的一个更特殊的版本。在这一章中,读者将学习这一文法,学习如何重定义函数,以及理解构造和析构对于继承和组合的重要性。
  第15章  多态性和虚函数。单靠读者自己,可能要花九个月的时间才能发现和理解OOP的这一基石。通过一些小而简单的例子,读者可以看到如何通过继承创建一个类型族,看到在这个类型族中如何通过公共基类对这个族中的对象进行操作。关键字virtual使程序员能够按类属处理这个族中的所有对象,这意味着大块代码将不依赖于特殊类型的信息,因此,程序是可扩充的,构造程序和维护代码也变得更容易和更便宜。
  第16章  模板介绍。继承和组合允许程序员重用对象代码,但不能解决有关重用需要的所有问题。模板通过为编译器提供了一种在类或函数体中代换类型名的方法,来允许程序员重用源代码。这就支持了容器类库的使用,容器类库是使我们能快速而有效地开发面向对象程序的重要工具(标准C++库包含了一个重要的容器类库)。这一章给出了这个基本主题的详尽阐述。
  另一些主题(更高级的课题),可以在本书的第2卷中看到,本书的第2卷可以从网站www.BruceEckel.com下载。

0.6  练习
  我已经发现,在课堂讨论期间,练习对同学们的完全理解是特别有用的,因此,本书的每章后面都有一组练习。练习题的数量在第1版的基础上有很大的增加。
  在这些练习中,很多是比较简单的,可以在课堂内或实验室内用合理的时间完成,老师可以通过观察证实所有的学生正在吸收这些材料。有些练习是为了激发优秀学生的学习兴趣。大量练习被设计成能在短期内求解,目的是为了测试和完善学生所掌握的知识,而不是提出主要的挑战(也许我们将自己找到那些挑战,更可能的是,那些挑战会自动出现在我们面前)。
  0.6.1  练习的答案
  部分练习题的答案可以在本书的电子文档“Thinking in C++ Annotated Solution Guide”中找到,只需支付很少的费用就可以从网站www.BruceEckel.com上获得这个电子文档。

0.7  源代码
  本书中的源代码是免费软件版权,通过网站www.BruceEckel.com分发。该版权防止未经允许用印刷媒体重印这些代码,但是,在许多其他情况下可以使用这些代码(见下)。
  这些代码放在一个压缩文件中,可以从任何有zip工具的平台上提取(如果没有安装合适的平台,可以从Internet上找到适合你的平台的某个版本)。在解压缩的首目录上,我们可以找到如下所示的版权声明:
  读者可以在自己的项目中和在课堂上使用这些代码,只要遵守以上的版权声明。

0.8  语言标准
  在本书中,当谈到遵循ISO C标准时,我一般只是说‘C’。只有当有必要区别标准C和老的、以前版本的C时,我才加以区分。
  在写这本书时,C++标准委员会完成了语言的标准化工作。这样,我将用术语“标准C++”来指代这个标准化的语言。如果我简单地谈到C++,读者就应该假设这意味着“标准C++”。
  在C++标准委员会的实际名字与标准本身的名字之间有些混淆。委员会的主席Steve Clamage就此作了如下澄清:
  有两个C++标准委员会:NCITS(以前的X3)J16委员会和ISO JTC1/SC22/WG14委员会。ANSI授权NCITS建立制订美国国家标准的技术委员会。
  1989年J16受委托制订C++美国标准。1991年WG14受委托制订国际标准。J16项目转变为“Type I”(国际)项目,并服从于ISO标准化计划。
  这两个委员会在同一时间、同一地点开会,J16的投票作为美国在WG14的票数。WG14委派J16做技术工作,并对J16的技术工作进行表决。
  最初,C++标准是作为ISO标准制订的。ANSI后来投票(在J16的建议下)决定采用ISO C++标准作为C++美国标准。
  因此,“ISO”是称呼C++标准的正确方式。
  0.8.1  语言支持
  读者的编译器可能不支持在本书中讨论的所有特征,如果还没有编译器的最新版本就更是如此了。实现像C++这样的语言是艰巨的任务,而且读者可能希望将这些特征划分成一些部分后分别出现,而不是一下子全出现。如果读者试用本书中的某个例子,从编译器中得到了大量的错误,这可能不是代码或编译错误,而可能是他的特定编译器还没有实现例子中的某个特征。

0.9  本书的CD ROM
  本书附带的CD ROM的主要内容是一个“CD ROM课堂讨论”。题目是“Thinking in C: Foundations for Java & C++”,由Chuck Allison编写(MindView, Inc.出版)。这些内容包含几小时的讲课录音和幻灯片,如果读者有CD ROM播放机和音响系统,就能在大多数计算机上观看。Thinking in C的目标是让读者关注整个C语言的基础。它的重点放在使读者能够转移到C++或Java语言所必需的知识上,而不是试图使读者在C的所有问题上都成为专家。(使用诸如C++或Java高级语言的原因之一,正是我们能因而避开许多犄角旮旯的问题。)它还包括练习和答案。请记住,因为本书的第3章超出了“Thinking in C”的CD ROM的内容,所以这个CD ROM不能代替这一章,但它应当用做本书的预备知识。
  请注意,这个CD ROM是基于浏览器的,所以读者应当先安装Web浏览器。

0.10  CD ROM、课堂讨论和咨询
  CD ROM上有一些课堂讨论,覆盖了本书的第1卷和第2卷。它包括几小时的我的讲课录音,配套幻灯片,包含本书每一章选用的材料。如果读者有CD ROM播放机和音响系统,就能在大多数计算机上观看。这些CD ROM可以在网站www.BruceEckel.com购买,同时那里还可以发现更多的信息和示范讲义。
  我的公司MindView, Inc提供基于本书的材料以及高级主题的公开课堂讨论。从每一章选取的材料代表一课,后面有一个检测练习的阶段,这样每个学生能得到指导。我们还提供现场培训、咨询、辅导、设计和代码演练的服务。
  我有时做设计咨询、项目评价和代码演练。我第一次写计算机程序时,我的最初动机是使我的咨询活动更好,因为我发现咨询是富有挑战性的、具有教育意义的和最愉快的个人经历。这样,我将竭尽全力为满足客户要求而安排日程,或者向你推荐我的一个合作者(这些人是我熟悉的和信任的伙伴,他们常常与我一起工作和举办课堂讨论)。

0.11  错误
  无论一个作者具有多少发现错误的技巧,总会有一些错误漏网,它们常常能被新读者发现。如果读者发现了任何认为是错误的地方,请填写网站www.BruceEckel.com上关于本书的修改表格并在线提交,我将非常感激。

0.12  关于封面
  这本书的第1版的封面上有我的头像,但是我最初希望第2版的封面能像《Java编程思想》一样更加像个艺术品。由于某些原因,在我看来C++似乎隐含着装饰艺术,具有简单的线条并刷过铬黄的颜料。在我的脑海中会浮现出像轮船和飞机这样的招贴画,上面是长长的流线体。
  我的朋友Daniel Will-Harris (www.Will-Harris.com)与我初识于初中的唱诗班,现在他已经成了世界级的设计师和作者。他已经实际上为我做了所有的设计,包括这本书第1版的封面。在这一版封面的设计过程中,Daniel不满意我们正在制作的进程,不停地问:“怎样才能体现人与计算机的关系呢?”我们卡壳了。
  他突发奇想,让我把自己的头像放在屏幕上。Daniel有一个图像程序(Corel Xara, 他的至爱),能自动勾勒我的头像的扫描图。正如他所描述的,“自动勾勒是一种计算机方法,能将图片变为一些逼真线条。”然后他开始工作,直到使我的头像看上去像一张地形图,这个图像可能就是计算机眼中人的形象吧。
  我看了这个图像,将它影印在水彩画纸上,然后通过在图像上增加水彩开始创造大量实验。我挑选了最喜欢的几幅图像,然后Daniel再把它们扫描回来,安排在封面上,又增加了文字和其他内容。整个过程花了几个月,主要是涂水彩的时间。但是我特别高兴,因为我参与了封面艺术设计,激励我做了大量的水彩画。

0.13  感谢
  首先,感谢在Internet上提交修改和建议的每一位读者,这对于改进本书的质量起了重要的帮助作用。特别要感谢John Cook。
  本书中的思想和观点来源于许多方面,包括:我的朋友,例如Chuck Allison、Andrea Provaglio、Dan Saks、Scott Meyers、Charles Petzold和Michael Wilk;C++语言的倡导者,例如Bjarne Stroustrup、Andrew Koenig和Rob Murray;C++标准委员会的成员,例如Nathan Myers (他给出特别的帮助和毫无保留的见解)、Bill Plauger、Reg Charney、Tom Penello、Tom Plum、Sam Druker和Uwe Steinmueller;在软件开发会议上对我的C++教学发表过见解的学者;在我的课堂上参与讨论的学生,我认真地听取他们提出的问题,以使这本教材更加清晰易懂。
  我对我的朋友Gen Kiyooka深表感谢,他的公司Digigami为我提供了Web服务器。
  我的朋友Richard Hale Shaw和我一起教授C++; Richard(还有Kim)的见解和支持对我很有帮助。我还要感谢KoAnn Vikoren、Eric Faurot、Jennifer Jessup、Tara Arrowood、Marco Pardi、Nicole Freeman、Barbara Hanscome、Regina Ridley、Alex Dunne以及MFI的全体人员。
  我特别感谢我的所有老师和所有学生(他们也是我的老师)。
  还要感谢为这本书作出贡献的John Irving、Neal Stephenson、Robertson Davies (我们会思念你)、Tom Robbins、William Gibson、Richard Bach、Carlos Castaneda和 Gene Wolfe。
  Python语言的发明者Guido van Rossum将他的发明无私地贡献给了全世界。他的贡献使我受益。
  感谢Prentice Hall的工作人员:Alan Apt、Ana Terry、Scott Disanno、Toni Holm以及我的电子版编辑Stephanie English。在市场营销方面,还要感谢Bryan Gambrel和Jennie Burger。
  Sonda Donovan帮助制作CD ROM产品。Daniel Will-Harris在盘片上创造了丝网装璜设计。
  感谢Crested Butte中友好的人们,他们构筑了这么一个奇妙的地方,特别是Al Smith(很棒的咖啡乐园的创造者)、我的邻居们Dave & Erika、Heg地方书店的Marsha、Teocalli Tamale的Pat & John 、面包咖啡馆的Sam,以及帮助我进行音频研究的Tiller。还要感谢Camp4的所有充满激情的人们,使我的每一个早晨都是如此美妙。
  为我提供帮助的朋友包括:Zack Urlocker、Andrew Binstock、Neil Rubenking、 Kraig Brockschmidt、Steve Sinofsky、JD Hildebrandt、Brian McElhinney、Brinkley Barr、Larry O'Brien、“子夜工程杂志”的Bill Gates、Larry Constantine、Lucy Lockwood、 Tom Keffer、Dan Putterman、Gene Wang、Dave Mayer、David Intersimone、Claire Sawyers、意大利的朋友们(Andrea Provaglio、Rossella Gioia、Laura Fallai、Marco & Lella Cantu、Corrado、Ilsa和Christina Giustozzi)、Chris和Laura Strand (和Parker)、the Almquists、Brad Jerbic、Marilyn Cvitanic、the Mabrys、the Haflingers、the Pollocks、Peter Vinci、the Robbins、the Moelters、Dave Stoner、Laurie Adams、the Cranstons、Larry Fogg、Mike和Karen Sequeira、Gary Entsminger和Allison Brody、Kevin、Sonda, & Ella Donovan、Chester和Shannon Andersen、Joe Lordi、Dave和Brenda Bartlett、the Rentschlers、Lynn和Todd, 以及他们的家庭等等,当然还包括我的父母。

作者简介

Bruce Eckel:Bruce Eckel:  Bruce Eckel 是MindView公司 (www.MindView.net) 的总裁,向客户提供软件咨询和培训。他是C++标准委员会拥有表决权的成员之一。他也是《Java编程思想》(该书第3版影印版及翻译版已由机械工业出版社引进出版)、《C++编程思想 第1卷》及其他C++著作的作者,已经发表了150多篇论文 (其中有许多C++语言方面的论文) ,他经常参加世界各地的研讨会并进行演讲。

译者简介

刘宗田 袁兆山 潘秋菱 等:刘宗田: 上海大学教授,博士生导师。中国机械工程学会高级会员、中国电子学会高级会员、安徽省计算机学会理事、安徽省电子学会理事、安徽省电子学会计算机应用专业委员会主任委员。 1970年毕业于北京航天航空大学,1982年毕业于北京航空航天大学计算机科学与工程系,获硕士学位。所学专业为计算机软件,现从事专业为计算机应用技术。技术专长与现研究方向为人工智能应用、软件工程。
袁兆山: 教授,合肥工业大学计算机与信息学院软件工程研究室主任,中国电机工程学会高级会员,安徽省电机工程学会理事,计算机专委会副主任、秘书长。从事计算机应用,计算机软件与理论专业本科、硕士、博士研究生的教学和该方向的科学研究与应用项目开发。 目前从事的研究方向是基于知识的智能软件工程环境、网络与MIS。主持和参加了国家自然科学基金、部发展基金及省自然科学基金等各种基金项目20多项;已完成并鉴定16项、获奖项目8项,其中部科技进步三等奖1项、部司科技进步一等奖1项、科技进步奖2项、评为安徽省重大科研成果2项。已发表学术论文100多篇、获得安徽省自然科学优秀学术论文二、三等奖,部级优秀学术论文奖和进入EI论文20多篇。已经出版专著2部、译著、教材多部。

译者序

作为译者,我有幸组织翻译了《C++编程思想》第1版。在这之前,我仅仅耳闻这是一本别具特色的畅销书,至于如何别具特色,如何得以畅销,并不十分清楚。在第1版的翻译过程中,我逐渐领悟了Eckel编写技巧的真谛。在第1版中文版的译者序中,我曾这样总结他的技巧:“其内容、讲授方法、选用例子和跟随的练习,别具特色。原书作者不是按传统的方法讲解C++的概念和编程方法,而是根据他自己过去学习C++的亲身体会,根据他多年教学中从他的学生们的学习中发现的问题,用一些非常简单的例子和简练的叙述,阐明了在学习C++中特别容易混淆的概念。特别是,他经常通过例子引导读者从C++编译实现的汇编代码的角度反向审视C++的语法和语义,常常使读者有‘心有灵犀一点通’的奇特效果,这在以往的C++书中并不多见。”
  《C++编程思想》第1版的中文版自2000年1月第1次印刷以来,在中国市场上的畅销势头经久不衰。这充分说明了这本书在中国读者心目中的地位。
  Eckel致力于计算机程序设计语言教学数十年,而且是全心全意地从事这项工作,这本身就是难能可贵的,是他成功的根本原因。另外,他的成功还有赖于他的精益求精的精神,这不仅表现在第1版的与众不同的精心选材和认真推敲的叙述方面,也体现在第2版与第1版的不同点上。
  表面上,第2版与第1版并无太多的变化,但是通过分析,可以看出,其中的任何变化都是经过深思熟虑的。从章节上看,最大的区别是增加了两章和去掉了四章。增加的两章分别是“对象的创建与使用”和“C++中的C”。前者与“对象导言”实际上是第1版的“对象的演化”一章的彻底重写,增加了近几年面向对象方法和编程方法的最新研究与实践的丰硕成果。后者的添加不仅使不熟悉C的读者直接使用这本书成为可能,而且C本身就是C++的组成部分,这是C++得以成功的主要原因之一。删去的四章是“输入输出流介绍”、“多重继承”、“异常处理”和“运行时类型识别”。这四章属于C++中较复杂的主题,作者将它们连同C++标准完成后又增加的一些内容放到这本书的第2卷中。这样就使得这本书的第1卷内容更加集中,一般的读者可以不被这些复杂内容所困扰,而需要这些复杂知识的读者可以阅读这本书的第2卷。
实际上,第2版的改变不仅仅在于这些章节的调整,更多的改变体现在每一章中,包括例子的调整和练习的补充。这本书更成熟了。
  受机械工业出版社华章分社计算机编辑部委托,我又承担起《C++编程思想》第2版的翻译组织任务。翻译这样的成功之作,既是机遇,更是压力。有如此众多的读者阅读我们翻译的作品,无论如何这是令人高兴的事情。诚然,吸引读者的魅力来源于原作,而不是我们的翻译技巧,但是能将如此光辉灿烂的作品变成中文版本,奉献给中国的读者,这其中毕竟融入了我们的心血,而且,第1版中文版的畅销,已经充分证明,并未因我们翻译水平的限制而黯淡了原作的光芒,这对我们已经够宽慰的了。然而,百万双眼睛在阅读这本书的同时也在审视我们的翻译水平,这就足以使我们诚惶诚恐的了。 翻译在某种意义上是再创作的过程,读者见仁见智。为求更多的满意,我们只有尽力而为。由于时间和水平限制,翻译错误在所难免,恳请读者指正。
参加第2版翻译和审校工作的人员包括:刘宗田、韩冬、蔡烈斌、袁兆山、潘秋菱、许东、李航、肖苑、刘璐、姜桂华、张卿、邵坤、陈慧琼、何允如、贾亮、童朝柱、邢大红、潘飚、刘莹、姜川、冯鸿等。
  感谢为本书第1版和第2版中文版作出贡献的所有朋友。感谢关心和支持本书翻译出版的广大读者。

刘宗田
2002.8.10

图书目录

第1章  对象导言 1
1.1  抽象的过程 1
1.2  对象有一个接口 2
1.3  实现的隐藏 4
1.4  实现的重用 5
1.5  继承:重用接口 5
1.5.1  is-a 关系和is-like-a 关系 8
1.6  具有多态性的可互换对象 8
1.7  创建和销毁对象 11
1.8  异常处理:应对错误 12
1.9  分析和设计 12
1.9.1  第0阶段:制定计划 14
1.9.1.1  任务陈述 14
1.9.2  第1阶段:我们在做什么 14
1.9.3  第2阶段:我们将如何建立对象 16
1.9.3.1  对象设计的五个阶段 17
1.9.3.2  对象开发准则 18
1.9.4  第3阶段:创建核心 18
1.9.5  第4阶段:迭代用例 19
1.9.6  第5阶段:进化 19
1.9.7  计划的回报 20
1.10  极限编程 20
1.10.1  先写测试 21
1.10.2  结对编程 22
1.11  为什么C++会成功 22
1.11.1  一个较好的C 22
1.11.2  延续式的学习过程 23
1.11.3  效率 23
1.11.4  系统更容易表达和理解 23
1.11.5  尽量使用库 23
1.11.6  利用模板的源代码重用 24
1.11.7  错误处理 24
1.11.8  大型程序设计 24
1.12  为向OOP转变而采取的策略 24
1.12.1  指导方针 25
1.12.1.1  训练 25
1.12.1.2  低风险项目 25
1.12.1.3  来自成功的模型 25
1.12.1.4  使用已有的类库 25
1.12.1.5  不要用C++重写已有的代码 25
1.12.2  管理的障碍 25
1.12.2.1  启动的代价 26
1.12.2.2  性能问题 26
1.12.2.3  常见的设计错误 26
1.13  小结 27
第2章  对象的创建与使用 28
2.1  语言的翻译过程 28
2.1.1  解释器 28
2.1.2  编译器 29
2.1.3  编译过程 29
2.1.3.1  静态类型检查 30
2.2  分段编译工具 30
2.2.1  声明与定义 30
2.2.1.1  函数声明的语法 31
2.2.1.2  一点说明 31
2.2.1.3  函数的定义 31
2.2.1.4  变量声明的语法 32
2.2.1.5  包含头文件 33
2.2.1.6  标准C++ include 语句格式 33
2.2.2  连接 34
2.2.3  使用库文件 34
2.2.3.1  连接器如何查找库 34
2.2.3.2  秘密的附加模块 35
2.2.3.3  使用简单的C语言库 35
2.3  编写第一个C++程序 35
2.3.1  使用iostream类 35
2.3.2  名字空间 36
2.3.3  程序的基本结构 37
2.3.4 “Hello, World!” 37
2.3.5  运行编译器 38
2.4  关于输入输出流 38
2.4.1  字符数组的拼接 39
2.4.2  读取输入数据 39
2.4.3  调用其他程序 40
2.5  字符串简介 40
2.6  文件的读写 41
2.7  vector简介 42
2.8  小结 45
2.9  练习 46
第3章  C++中的C 47
3.1  创建函数 47
3.1.1  函数的返回值 48
3.1.2  使用C的函数库 49
3.1.3  通过库管理器创建自己的库 49
3.2  执行控制语句 50
3.2.1  真和假 50
3.2.2  if-else语句 50
3.2.3  while语句 51
3.2.4  do-while语句 51
3.2.5  for语句 52
3.2.6  关键字break 和 continue 53
3.2.7  switch语句 54
3.2.8  使用和滥用goto 55
3.2.9  递归 55
3.3  运算符简介 56
3.3.1  优先级 56
3.3.2  自增和自减 57
3.4  数据类型简介 57
3.4.1  基本内部类型 57
3.4.2  bool类型与true和false 58
3.4.3  说明符 59
3.4.4  指针简介 60
3.4.5  修改外部对象 62
3.4.6  C++引用简介 64
3.4.7  用指针和引用作为修饰符 65
3.5  作用域 66
3.5.1  实时定义变量 67
3.6  指定存储空间分配 68
3.6.1  全局变量 68
3.6.2  局部变量 69
3.6.2.1  寄存器变量 69
3.6.3  静态变量 70
3.6.4  外部变量 71
3.6.4.1  连接 71
3.6.5  常量 72
3.6.5.1  常量值 72
3.6.6  volatile变量 73
3.7  运算符及其使用 73
3.7.1  赋值 73
3.7.2  数学运算符 73
3.7.2.1  预处理宏介绍 74
3.7.3  关系运算符 75
3.7.4  逻辑运算符 75
3.7.5  位运算符 75
3.7.6  移位运算符 76
3.7.7  一元运算符 78
3.7.8  三元运算符 78
3.7.9  逗号运算符 79
3.7.10  使用运算符时的常见问题 79
3.7.11  转换运算符 80
3.7.12  C++的显式转换 80
3.7.12.1  静态转换(static_cast) 81
3.7.12.2  常量转换(const_cast) 82
3.7.12.3  重解释转换(reinterpret_cast) 82
3.7.13  sizeof—独立运算符 83
3.7.14  asm 关键字 84
3.7.15  显式运算符 84
3.8  创建复合类型 84
3.8.1  用typedef命名别名 85
3.8.2  用struct把变量结合在一起 85
3.8.2.1  指针和struct 87
3.8.3  用enum提高程度清晰度 87
3.8.3.1  枚举类型检查 88
3.8.4  用union节省内存 88
3.8.5  数组 89
3.8.5.1  指针和数组 91
3.8.5.2  探究浮点格式 93
3.8.5.3  指针算术 94
3.9  调试技巧 96
3.9.1  调试标记 96
3.9.1.1  预处理器调试标记 97
3.9.1.2  运行期调试标记 97
3.9.2  把变量和表达式转换成字符串 98
3.9.3  C语言assert( )宏 98
3.10  函数地址 99
3.10.1  定义函数指针 99
3.10.2  复杂的声明和定义 99
3.10.3  使用函数指针 100
3.10.4  指向函数的指针数组 101
3.11  make:管理分段编译 101
3.11.1  make的行为 102
3.11.1.1  宏 102
3.11.1.2  后缀规则 103
3.11.1.3  默认目标 103
3.11.2  本书中的makefile 104
3.11.3  makefile的一个例子 104
3.12  小结 106
3.13  练习 106
第4章  数据抽象 109
4.1  一个袖珍C库 109
4.1.1  动态存储分配 112
4.1.2  有害的猜测 114
4.2  哪儿出问题 115
4.3  基本对象 116
4.4  什么是对象 120
4.5  抽象数据类型 121
4.6  对象细节 121
4.7  头文件形式 122
4.7.1  头文件的重要性 122
4.7.2  多次声明问题 123
4.7.3  预处理器指示#define、#ifdef和#endif 124
4.7.4  头文件的标准 124
4.7.5  头文件中的名字空间 125
4.7.6  在项目中使用头文件 125
4.8  嵌套结构 126
4.8.1  全局作用域解析 128
4.9  小结 129
4.10  练习 129
第5章  隐藏实现 132
5.1  设置限制 132
5.2  C++的访问控制 132
5.2.1  protected说明符 134
5.3  友元 134
5.3.1  嵌套友元 136
5.3.2  它是纯面向对象的吗 138
5.4  对象布局 138
5.5  类 139
5.5.1  用访问控制来修改Stash 141
5.5.2  用访问控制来修改Stack 141
5.6  句柄类 142
5.6.1  隐藏实现 142
5.6.2  减少重复编译 142
5.7  小结 144
5.8  练习 144
第6章  初始化与清除 146
6.1  用构造函数确保初始化 146
6.2  用析构函数确保清除 147
6.3  清除定义块 149
6.3.1  for循环 150
6.3.2  内存分配 151
6.4  带有构造函数和析构函数的Stash 152
6.5  带有构造函数和析构函数的Stack 154
6.6  集合初始化 156
6.7  默认构造函数 158
6.8  小结 159
6.9  练习 159
第7章  函数重载与默认参数 161
7.1  名字修饰 162
7.1.1  用返回值重载 162
7.1.2  类型安全连接 162
7.2  重载的例子 163
7.3  联合 166
7.4  默认参数 168
7.4.1  占位符参数 169
7.5  选择重载还是默认参数 170
7.6  小结 173
7.7  练习 173
第8章  常量 175
8.1  值替代 175
8.1.1  头文件里的const 176
8.1.2  const的安全性 176
8.1.3  集合 177
8.1.4  与C语言的区别 177
8.2  指针 178
8.2.1  指向const的指针 179
8.2.2  const指针 179
8.2.2.1  格式 180
8.2.3  赋值和类型检查 180
8.2.3.1  字符数组的字面值 180
8.3  函数参数和返回值 181
8.3.1  传递const值 181
8.3.2  返回const值 181
8.3.2.1  临时量 183
8.3.3  传递和返回地址 183
8.3.3.1  标准参数传递 185
8.4  类 185
8.4.1  类里的const 186
8.4.1.1  构造函数初始化列表 186
8.4.1.2  内部类型的“构造函数” 187
8.4.2  编译期间类里的常量 188
8.4.2.1  旧代码中的“enum hack” 189
8.4.3  const对象和成员函数 190
8.4.3.1  可变的:按位const和按逻辑const 192
8.4.3.2  只读存储能力 193
8.5  volatile 194
8.6  小结 195
8.7  练习 195
第9章  内联函数 197
9.1  预处理器的缺陷 197
9.1.1  宏和访问 199
9.2  内联函数 200
9.2.1  类内部的内联函数 200
9.2.2  访问函数 201
9.2.2.1  访问器和修改器 202
9.3  带内联函数的Stash和Stack 205
9.4  内联函数和编译器 208
9.4.1  限制 209
9.4.2  向前引用 209
9.4.3  在构造函数和析构函数里隐藏行为 210
9.5  减少混乱 210
9.6  预处理器的更多特征 211
9.6.1  标志粘贴 212
9.7  改进的错误检查 212
9.8  小结 215
9.9  练习 215
第10章  名字控制 217
10.1  来自C语言中的静态元素 217
10.1.1  函数内部的静态变量 217
10.1.1.1  函数内部的静态对象 218
10.1.1.2  静态对象的析构函数 219
10.1.2  控制连接 220
10.1.2.1  冲突问题 221
10.1.3  其他存储类型说明符 222
10.2  名字空间 222
10.2.1  创建一个名字空间 222
10.2.1.1  未命名的名字空间 223
10.2.1.2  友元 224
10.2.2  使用名字空间 224
10.2.2.1  作用域解析 224
10.2.2.2  使用指令 225
10.2.2.3  使用声明 226
10.2.3  名字空间的使用 227
10.3  C++中的静态成员 228
10.3.1  定义静态数据成员的存储 228
10.3.1.1  静态数组的初始化 229
10.3.2  嵌套类和局部类 231
10.3.3  静态成员函数 232
10.4  静态初始化的相依性 234
10.4.1  怎么办 235
10.4.1.1  技术一 235
10.4.1.2  技术二 237
10.5  替代连接说明 240
10.6  小结 240
10.7  练习 241
第11章  引用和拷贝构造函数 244
11.1  C++中的指针 244
11.2  C++中的引用 244
11.2.1  函数中的引用 245
11.2.1.1  常量引用 246
11.2.1.2  指针引用 246
11.2.2  参数传递准则 247
11.3  拷贝构造函数 247
11.3.1  按值传递和返回 247
11.3.1.1 传递和返回大对象 248
11.3.1.2 函数调用栈框架 248
11.3.1.3  重入 249
11.3.1.4  位拷贝与初始化 249
11.3.2  拷贝构造函数 251
11.3.2.1  临时对象 254
11.3.3  默认拷贝构造函数 255
11.3.4  替代拷贝构造函数的方法 256
11.3.4.1  防止按值传递 257
11.3.4.2  改变外部对象的函数 257
11.4  指向成员的指针 257
11.4.1  函数 259
11.4.1.1  一个例子 259
11.5  小结 261
11.6  练习 261
第12章  运算符重载 264
12.1  两个极端 264
12.2  语法 264
12.3  可重载的运算符 265
12.3.1  一元运算符 266
12.3.1.1  自增和自减 269
12.3.2  二元运算符 269
12.3.3  参数和返回值 278
12.3.3.1  作为常量通过传值方式返回 279
12.3.3.2  返回值优化 279
12.3.4  不常用的运算符 280
12.3.4.1  operator, 280
12.3.4.2  operator-> 280
12.3.4.3  嵌入的迭代器 282
12.3.4.4  operator->* 284
12.3.5  不能重载的运算符 285
12.4  非成员运算符 286
12.4.1  基本方针 287
12.5  重载赋值符 287
12.5.1  operator=的行为 288
12.5.1.1  类中指针 289
12.5.1.2  引用计数 291
12.5.1.3  自动创建operator= 295
12.6  自动类型转换 296
12.6.1  构造函数转换 296
12.6.1.1  阻止构造函数转换 297
12.6.2  运算符转换 297
12.6.2.1  反身性 298
12.6.3  类型转换例子 299
12.6.4  自动类型转换的缺陷 300
12.6.4.1  隐藏的行为 301
12.7  小结 302
12.8  练习 302
第13章  动态对象创建 305
13.1  对象创建 305
13.1.1  C从堆中获取存储单元的方法 306
13.1.2  operator new 307
13.1.3  operator delete 307
13.1.4  一个简单的例子 308
13.1.5  内存管理的开销 308
13.2  重新设计前面的例子 309
13.2.1  使用delete void*可能会出错 309
13.2.2  对指针的清除责任 310
13.2.3  指针的Stash 310
13.2.3.1  一个测试程序 312
13.3  用于数组的new和delete 314
13.3.1  使指针更像数组 315
13.4  耗尽内存 315
13.5  重载new和delete 316
13.5.1  重载全局new和delete 317
13.5.2  对于一个类重载new和delete 318
13.5.3  为数组重载new和delete 320
13.5.4  构造函数调用 322
13.5.5  定位new和delete 323
13.6  小结 324
13.7  练习 324
第14章  继承和组合 326
14.1  组合语法 326
14.2  继承语法 327
14.3  构造函数的初始化表达式表 329
14.3.1  成员对象初始化 329
14.3.2  在初始化表达式表中的内部类型 329
14.4  组合和继承的联合 330
14.4.1  构造函数和析构函数调用的次序 331
14.5  名字隐藏 333
14.6  非自动继承的函数 336
14.6.1  继承和静态成员函数 339
14.7  组合与继承的选择 339
14.7.1 子类型设置 340
14.7.2  私有继承 342
14.7.2.1  对私有继承成员公有化 342
14.8  protected 343
14.8.1  protected继承 343
14.9  运算符的重载与继承 343
14.10  多重继承 345
14.11  渐增式开发 345
14.12  向上类型转换 346
14.12.1  为什么要“向上类型转换” 347
14.12.2  向上类型转换和拷贝构造函数 347
14.12.3  组合与继承(再论) 349
14.12.4  指针和引用的向上类型转换 350
14.12.5  危机 350
14.13  小结 351
14.14  练习 351
第15章  多态性和虚函数 354
15.1  C++程序员的演变 354
15.2  向上类型转换 355
15.3  问题 356
15.3.1  函数调用捆绑 356
15.4  虚函数 356
15.4.1  扩展性 357
15.5  C++如何实现晚捆绑 359
15.5.1  存放类型信息 360
15.5.2  虚函数功能图示 361
15.5.3  撩开面纱 362
15.5.4  安装vpointer 363
15.5.5  对象是不同的 363
15.6  为什么需要虚函数 364
15.7  抽象基类和纯虚函数 365
15.7.1  纯虚定义 368
15.8  继承和VTABLE 368
15.8.1  对象切片 370
15.9  重载和重新定义 372
15.9.1  变量返回类型 373
15.10  虚函数和构造函数 375
15.10.1  构造函数调用次序 375
15.10.2  虚函数在构造函数中的行为 376
15.11  析构函数和虚拟析构函数 376
15.11.1  纯虚析构函数 378
15.11.2  析构函数中的虚机制 379
15.11.3  创建基于对象的继承 380
15.12  运算符重载 382
15.13  向下类型转换 384
15.14  小结 386
15.15  练习 387
第16章  模板介绍 390
16.1  容器 390
16.1.1  容器的需求 391
16.2  模板综述 392
16.2.1  模板方法 393
16.3  模板语法 394
16.3.1  非内联函数定义 395
16.3.1.1  头文件 396
16.3.2  作为模板的IntStack 396
16.3.3  模板中的常量 398
16.4  作为模板的Stash和Stack 399
16.4.1  模板化的指针Stash 401
16.5  打开和关闭所有权 405
16.6  以值存放对象 407
16.7  迭代器简介 408
16.7.1  带有迭代器的栈 415
16.7.2  带有迭代器的PStash 417
16.8  为什么使用迭代器 422
16.8.1  函数模板 424
16.9  小结 425
16.10  练习 425
附录A  编码风格 428
A.1  常规 428
A.2  文件名 428
A.3  开始和结束注释标记 429
A.4  圆括号、大括号和缩排 429
A.5  标识符名 432
A.6  头文件的包含顺序 432
A.7  在头文件上包含警卫 432
A.8  使用名字空间 433
A.9  require( )和assure( )的使用 433
附录B  编程准则 434
附录C  推荐读物 441
C.1  C 441
C.2  基本C++ 441
C.2.1  我自己的书 441
C.3  深入研究和死角分析 442
C.4  分析和设计 443
索引 445

教学资源推荐
作者: Mario Hewardt Daniel Pravat
作者: [美]基普·欧文(Kip Irvine) 著
作者: [美] 本贾尼?斯特劳斯特鲁普 (Bjarne Stroustrup)著
作者: (美)Y. Daniel Liang 著
参考读物推荐
作者: [英]拉乌尔·加布里埃尔·乌尔玛(Raoul-Gabriel Urma), 理查德·沃伯顿(Richard Warburton) 著
作者: [美]阿尔文·亚历山大(Alvin Alexander) 著
作者: Julie C. Meloni