第一章面向对象 第一部分C+基础 第一章面向对象 1.1简介 面向对象(Object-0 riented)已经成为90年代重要主题词之 可用如下说法简单地 表达面向对象的整体思路:先对特定问题建立通用的解决方案,然后再改制这些方案以适 应特定需要,这样的设计方法内在的优点是: ·能够直接地再利用他人已经设计并编写成功的程序,而不需要再作广泛的重新测试 。能够由基本而通用的解决方案派生出新的解决方案 ■能够建立一个由模块组成的系统 用实物作比拟会有助于弄清模块化系统的概念。比如一种组合型长椅,是按这样的结 构设计制造:适合某种特定需要,其中的一块或几块既可以加到长椅的椅架上且可以从椅 架上拿开,又不影响长椅本身的性能和设计上的美观.又比如 个模块化的房间,可以设 计得既容易得到扩展又不影响房子的基本结构。模块化系统与上述所列的比拟很相似,是 由包含系统基本功能的固定基组成的。这个固定基是待完善系统的构件,它容易扩展,新 的功能可从这个基派生出来,无需进行广泛的重新测试和编码。 面向对象的系统的主要缺点(如果称之为缺点的话),就是无法正确地设计一个足够 通用的解决方案来构成系统的基。因此,要建立一个强大而有用的面向对象的系统,使系 统具有长期的可用性是至关重要的。 C+是一种面向对象的编程语言。但如果系统没有采用面向对象的技术, C+只能 作为面向过程的语言来使用。为了将C+带人生活,读者必须考虑面向对象。在编写第 一行程序之前,必须尽力地花时间去思考系统的设计、 系统的基以及期望由系统基所派生 出来的解决方案。如果没有考虑到面向对象和模块化,那C+这种工具的面向对象强大 之处将变得毫无用处,因为没有去正确使用它。本章将教会读者在编程之前如何构思 1.2抽象 抽象是面向对象设计的核心思想.抽象的艺术在于抓住一个系统最核心的特性,这些 特性是能够表述以后发生的任何事情的构件,虽然抽象是一个简单易懂的概念,但读者会 惊讶地发现,在设计一些系统的时候,使用这种方法的频度几乎微乎其微!本章提供了 个极复杂系统的极简单的设计.我们的目的是要说明怎样把一个极复杂的问题更好地分: 成一些最简单的组成部分,又如何建立并修改一个已经用模块化风格分解产生的系统。 为简化起见,我们只考虑系统最通用的特性
第一章面向对象 1.3设计一个电讯系统 当您拿起话简给别人打电话时,在您和另一方之间就建立了一个连接。简单说,这 就是两点间的连接。您的目标就是要设计一个能获得这种连接的系统. 当然,实际生活中不会有这样简单的两点间的直接连接。所以我们要给系统增加一 些复杂性, 例如,假设您要给尼古拉挂个电话,通话线路可能有几种不同方式: ·您非常幸运地有一条直达热线接到尼古拉那里。在这种情况下,电话线路直接联接读 者和尼古拉: 读者 +尼古拉 (无问顺) ■您不得不经过另外一个地点的线路才可最终与尼古拉相接通,即: 卖者 太德 尼吉拉 在这种情况下,您到太德那里有一条直达线,而太德到尼古拉那里又有一条直达线。 为了将您和尼古拉连通,必须先经过太德 ■如果太德的线路处于忙的状态又会怎样呢?那就不能通过它来与尼古拉相连,这就必 须考虑其复杂性。读者的呼叫经由另外一条绕过太德的线路到达尼古拉那里.如: 读者一一一一一一+太铺 一+尼古拉 -(忙) +汤组 ■现在,看看最复杂的情况。在现实生活中,象我们刚才谈到的这些不同的连接(您。 太德,汤姆,尼古拉 实际上可认为是物理的硬连接的机器。用某种方式对这些机 器编程,使之能接受某种类型的电话呼叫,再将呼叫导向目的地。这种逻辑被编人机 器(从现在起,我们称这些机器为设备),以便能理解那些对它们的呼叫的类型.然 而,如果这些呼叫类型不同,那么设备就不知道如何处理,因而拒绝这些呼叫。从技 术上讲,不同类型的设备具有理解不同类型协议的能力,如果一个电话呼叫在逻辑上 不遵守这个设备能理解的协议,则该呼叫就会遭到拒绝 这样,在为某一呼叫进行路由选择的时候,必须鉴别一下要通过设备的性质,以确保 该设备确实有能力处理该呼叫并为之选择路径。 1.4电讯系统的再思考 如果读者再花点时间去重读上一段落,会发现在设计该系统的时候需要涉及以下几个 问题: ■怎样获得可能毗连或非眦连的两点间的连接 ■ 怎样获知不同设备的不同行为特及这些设备能确定连接的不同类型? ■如果在正常情况下选择的逻辑连接不可用,那么如何将该呼叫导向另外的设备? 下一步的任务就要把跟光集中在为实现本系统而要明确表达的各种不同类型对象的基 本特性上.我们试图简化上述问题的复杂性,简化结果如下:
第一章面向对象 3 。两点间最简单的连接就是彼此间毗连的两点的连接,它们之间就可以直通,因而要确 定的第一个对象是获得这种连接的本质 ·所有的设备的都要求最终能实现一种主要功能:将一个呼叫向前传递给下一点。因而 要确定的另一个对象是获得一个基本设备这一特征的本质。 ■反呼叫从一个设备导向另一个设备之前,第一个设备必须向下一个设备发送信息以询 问将呼叫发给下一个点是否可行. 下一个设备也必须给这个设各回送一个话当的应答 信息。如果该设备可行,发送呼叫的设备就将这个呼叫传递给它。如果不可行,那么 发送呼叫的设备戴要试图找到另一条路径.这样,就可以归纳成一种机制,在这种机 制下,上面所确定的对象彼此间能进行通讯 刚才所罗列的简单概括可以构成整个系统的骨架。 一且一个系统设计得能够满足所列 的要求,就有足够能力处理以后的复杂问题,在下一小节再详述. 1.5在基本抽象基础上建立系统 现在总结一下分析结果.在上一小节里,我们列举了两种对象的功能。在C+中,对 象的功能用一种称作类(C1ass)的形式来表达.用来构成其它类的类叫作基类(Base C1ass).在上 小节中,我们认定了两种用来确定该系统骨架的基类,这两种基类将构 成所有由它们派生出来的其它类。对这两种基类规定如下 ■获取在毗邻两点间传递呼叫所需规则的类。称之为C1asSA, ■获取用作呼叫路由选择的最基本设备的功能的类.称之为C1sB。 此外,我们还认定了这些类的对象彼此间进行通讯的机制,通过这些机制,完成呼叫 的完整路程 有了这些基本构成,我们就可以使系统更复杂些,并看到所设计的这些基类怎样成功 地处理这些情况。下面是该系统所要求的另外一些特性 ■一个呼叫可以在非毗连的两点间漫游,这是经过了其它连接才链在一起的。 我们从C1a55A派生出一个类来完成这种功能。这个派生类继承了明确表达两点间 一对一连接所要求的规则。但是,它包含有另外的方法,此方法中有明确表达更复杂的连 接所要求的规则。 ■各种不同类型的设备都可以加人到该系统中,用不同的方式来为一个呼叫选择路径。 然而,为呼叫进行路由选择的基本机制总是相同的, 我们通过从C1a5sB中派生出一些类的办法来完成该特性.这些派生类将继承最基本 设备的功能。然而,每一个派生类都应该增加一些独特的属性或方法来将该设备与其它设 备区分开。类之间彼此通讯的机制也就被确定下来 这就应该是在设计一个大系统时所用的基本思维模式。本系统将能足够灵活地处理完 整的路由选择和改变设备的属性所需的变化规则。这些变化将简单地通过修改派生类的应 用代码来实现 每个设备的方法都封装(encapsulate)在它所属的类中,如果系统中加人了新的 设备,而该设备没有明确描述的属性,那么它可以利用基类中说明的功能。这种特性通过 虚函数(virtual function)来表达. 一且这个新设备的属性通过多态性(polymor phism)被确定下来,那么这些虚函数就可被废弃(override)
4 第一章面向对象 现在我们调一下几个关键的短语和词汇,它们是:对象,类,基类,派生类,虚函 数以及多态性。 1.6结论 尽管这里对一个复杂系统作了极其简单的表达,但这正是我们所要阑明的观点。尽 可能地将复杂问题简化.在初始设计阶段把精力集中在主要的特性和需求上,而不是陷人 到不重要的细节中】 定要从系统的最根本处人手 一旦当读者能并用这种方法分析并获 得所需系统,读者会觉得,在系统的强大的基上构造系统是一件多么容易的事.系统的复 杂性往往掩盖了潜在的,用经建立和实现系统时的简单性。需要设计者花时间努力地思考 如何反复杂问题分解成最简单的形式,一旦能这样做,就会觉得其它什么事情都可按部就 班了. 另一方面,如果设计中有缺陷,那么就会感到,试图在这样的设计上构造系统会混乱 不堪。一个好的系统总是遵循正确的规则而一个设计得不好的系统最终将混乱得几乎无 法收拾,通常的结果是完全重来, 尽管本章是预备性的,建议读者在学习第二章之前能把第一章重读一遍(最好要慢 些)).我们在第二章讨论语言本身
第二章C+及编程基础 5 第二章C+及编程基础 2.1简介 在编写程序之前,必须懂得程序如何存储以及如何在计算机上运行.本章将描述什么 是程序,程序如何被计算机处理和执行,然后,我们格编写并执行一个简短的C艹程序。 2.2什么是程序设计? 。程序是用能够被计算机理解的一种语言编写的语句的集合 程序的正确执行通常会通过计算机得到某种输出结果。 C++程序包含对预先写好的代码的引用,这些预先写好的代码以库(libraries)的形 式存储.。可通讨特殊的语句把这些库包含到C++代码中 程序要经过编译器、链接器和装载器的处理 这些个别的实体只不过是存储在计算机中的不同类型的软件,是专门用来处理程序代 码的。所有这些处理的最终结果是产生能被计算机所认识并能被计算机运行的代码。 程序设计从开始到完成所需的步骤如下 第一步程序员进行计算机登录。 第二步程序员用喜爱的系统的编辑器编辑源程序。 第三步程序员把编辑好的源程序存人文件中,这个文件叫做源代码文件。 第四步程序员用适当的命令指示计算机编译源代码文件. 用来编译程序的命令因编程语言的不同而不同。例如,用来编译C+程序的命令与用 来编译BASIC程序的命令不同.如果使用的是菜单驱动系统,那么编译和运行程序的处 理只不过是在适当的菜单选项上敲击一下。 我们再继续前面的步骤,这就是编译开始后将会发生什么事情。 第五步编译器将源程序代码翻译成汇编语言格式,然后传给计算机汇编器。 第六步汇编器将汇编语言代码翻译成可重定位的目标码,并将这些目标码传送给链接 第七步链接器将程序引用的所有支持例程连接在一起。这些例程存在于运行库中或早已 存在于被程序所引用的预编译程序中,然后链接器产生源代码的最终版本,我们把它叫做 可执行代码。该代码被传给执行程序的装载器。 第八非运行程序 虽然,整个处理过程显得很长,但是这些步骤对于程序员来说大多数是透明的。需要 程序员做的只是以下几个步骤: 第一非产生一个包含源代码的文件 第二步输入编译命令,得到编译结果 第三步运行程序. 下面将要讨论源代码文件命名的约定,在保存源代码文件时,要遵守这些约定