第3章面向对象程序设计3.1面向对象程序设计思想3.1.1历史回顾1967年挪威计算中心的KistenNygaard和OleJohanDahl开发了Simula67语言,它提供了比子程序更高一级的抽象和封装,引入了数据抽象和类的概念,它被认为是第一个面向对象语言。20世纪70年代初,PaloAlto研究中心的AlanKay所在的研究小组开发出Smalltalk语言,之后又开发出Smalltalk-80,Smalltalk-80被认为是最纯正的面向对象语言,它对后来出现的面向对象语言,如Object-C,C++,Self,Eiffl都产生了深远的影响。随着面向对象语言的出现,面向对象程序设计也就应运而生且得到迅速发展。之后,面向对象不断向其他阶段渗透,1980年GradyBooch提出了面向对象设计的概念,之后面向对象分析开始。1985年,第一个商用面向对象数据库问世。1990年以来,面向对象分析、测试、度量和管理等研究都得到长足发展。实际上,“对象”和“对象的属性”这样的概念可以追溯到20世纪50年代初,它们首先出现于关于人工智能的早期著作中。但是出现了面向对象语言之后,面向对象思想才得到了迅速的发展。过去的几十年中,程序设计语言对抽象机制的支持程度不断提高:从机器语言到汇编语言,到高级语言,直到面向对象语言。汇编语言出现后,程序员就避免了直接使用0-1,而是利用符号来表示机器指令,从而更方便地编写程序;当程序规模继续增长的时候,出现了Fortran、C、Pascal等高级语言,这些高级语言使得编写复杂的程序变得容易,程序员们可以更好地对付日益增加的复杂性。但是,如果软件系统达到一定规模,即使应用结构化程序设计方法,局势仍将变得不可控制。作为一种降低复杂性的工具,面向对象语言产生了,面向对象程序设计也随之产生。3.1.2什么是面向对象程序设计首先我们要了解的是,什么是面向对象的程序设计方法OOP(ObjectOrientedProgramming),它与传统的结构化程序设计方法SP(StructureProgramming)的主要区别是什么。要弄清什么是OOP,则应了解和回顾一下传统的结构化程序设计方法及其设计思想、程序结构与特点,以便比较对照二者之间的差异,由此领会OOP对SP的继承、丰富、发展和突破。1.结构化程序设计思想结构化程序设计SP是60年代诞生的,以针对当时爆发的所谓“软件危机”的挑战,而在70、80年代遍及全球成为所有软件开发设计领域、每个程序员都广为采用的传统的结构化程序设计方法与技术的简称。它的产生和发展形成了现代软件工程学的基础。SP的总的设计思路是两点:一是自顶向下,层次化;二是逐步求精,精细化。其程序结构是按功能划分基本模块为树型结构,使模块间的关系尽可能简单、独立,并从而单独验证模块的正确性。每一模块均由顺序、选择和循环三种基本结构组合而成。综言之,此即所谓“模块化”。因此,SP的程序的基本特点是:第3章面向对象程序设计·21·a.按层次组织模块。(即战略上划分战役)b.每一模块只有一个入口,一个出口。(每一战役尽可能简单、明确)c.代码和数据分离实现。(战术上程序=数据结构+算法)SP实现上述战略战术的具体方法和技术是:使用局部变量和子程序。SP的优点可以概括为:a.子程序对程序其它部分没有或尽可能少的连带作用,从而为共享代码奠定基础。b.由于SP方法的模块化分解与功能抽象,自顶向下,分而治之的手段及技术,从而能有效地将一个复杂的、中大规模的程序系统的设计任务分成许多易于控制和处理、可独立编程的子任务、子程序模块。c.对于上述子程序或模块中的每一个都有一个清晰的抽象界面,它只说明:对应用程序设计者来说只需了解它做什么(Whattodo),而不必说明:它如何去做(Howtodo)。但从本质上说,由Pascal和C这样的程序设计推动的传统的SP仍是一种面向数据和过程的设计方法,它把数据和过程分离为相互独立的实体,用数据代表问题空间中的客体借以表达实际问题中的信息;程序代码则体现用于处理加工这些数据的算法。于是,程序员在编程时必须时刻考虑要处理的数据结构和类型,对不同的数据格式(结构和类型)即使要作同样的处理计算,或者对于相同的数据格式要作不同的处理都要编写不同的程序,可见,使用传统SP方法设计出来的程序或系统,其可重用的成分很少。另一方面,当把数据和代码作为不同的分离体时,总存在着用错误的数据调用正确的程序,或用正确的数据调用错误的程序的危险。因而,使数据与程序始终保持相容一致,已成为程序员的一个沉重的负担。这就是为什么在开发一个大型软件的过程中,如果用户在工程的中、后期对数据格式或实现方案提出任何改变请求时,变化摧毁了前面工作的一切,前功尽弃。2.面向对象程序设计思想为了克服和解决当今许多大型软件项目和系统设计都接近或达到了SP方法所难以控制处理和适应其变化的上述种种矛盾及问题而产生了OOP方法与技术。OOP吸取了SP的一切优点和长处,同时又正视和顺应现实世界由物质和意识两部分组成的这一普遍原理,将其映射到对象的解空间就是:具体事物——对象,抽象概念——类;而一个对象无非就是这样一个实体,它具有一个名字标识,并带有自身的状态(属性)和自身的功能(行为或方法)。世界上的所有事物(对象)就是如此奇妙地简单。这正是面向对象方法和技术所追求的目标:将世界上的问题尽可能简单化。事实上,用计算机求解的问题都是现实世界中的问题,它们无非都是由一些相互联系的,并处于不断运动变化的事物(即对象)所组成。每个具体对象都可用两个特征来把握:描述事物静态数据和可施于这些数据上的有限操作。也就是说,应当把数据结构和对数据的操作放在地起,作为一个相互依存不可分离的整体(即对象类)来处理(封装、信息隐蔽、数据抽象等)。并且要考虑不同事物即对象类之间的联系(消息、通讯、协议等)和事物即对象类的重用性和变化性(继承、多态等),这才更符合客观世界的本来面目。概言之,OOP与SP不同,它除了包纳了SP的一切优特点与机制外,同时又是一个引入若干强有力的、更能反映事物本质的新概念、新机制,从而开创了一个程序新天地的强大新方法。OOP的基本原理是:用问题领域的模型来模拟现实世界,从而设计出尽可能直接、自然地表示问题求解方法的软件,这样的软件系统由对象组成,而对象则是完整反映客观世界事物具有不可分割的静态属性(数据结构)与动态行为(方法)的,并且它们是既有联系又有变化发展的实体。OOP方法所涉及的新概念,在理论上最具一般性的对应物及其描述如下等等:·22·第3章面向对象程序设计a.对象——对客观世界事物的表示或描述,世界上任何具体事物均可称为对象。b.类——是一组对象的抽象定义(抽象概念、抽象数据类型)c.方法——对应于对象的功能。d.消息——对象之间通讯的途径。e.继承——对象间具有相同性和差异变化的关系。基于以上概念,面向对象就成了一个作为现实世界映射的封闭的缩微世界,一个对象具有自身的属性(私有数据成员)和可以为自己或别人工作的功能(方法、操作或称成员函数),它能通过发送消息与其它对象进行通讯,协同完成任务。OOP并不是用一两句话就可以精确定义描述清楚的一套方法与技术,然而在这里,我们还是非形式化地、笼统地说明和描述一下OOP的概念:OOP是SP、信息掩蔽、知识表示、并行处理领域等概念的继承和发展。OOP的特点是把系统设计成将所需要求解的问题分解成一些对象及对象间传递消息的符合客观世界规律的自然过程。OOP方法使程序员摆脱具体的数据格式和过程的束缚,将精力集中到对要处理的对象的设计和研究上,从而大大减少了软件开发的复杂度。OOP包括了功能抽象的抽象数据、信息隐蔽即封装等机理,使对象的内部实现与外界隔离,从而提供了更理想的模块化机制,大大减少了程序间的相互干扰和副作用。OOP的抽象数据类型——对象类及继承,则为我们提供了理想的高可重用性的软件成份和机制。此外,在人工智能领域中,若用OOP方法表示知识,则更接近于自然的客观世界的知识表示和认识论,因而不仅能表达描述非常复杂的客观事物和知识,而且具有模块性强、结构化程度高,便于分层实现,有利于实际开发和维护。因此OOP方法和技术的优特点将非常适合知识处理、知识库、专家系统等人工智能领域和数据库、CAD、图形处理(多媒体)、系统模拟与构造等大型复杂软件工程化开发。3.1.3面向对象程序设计语言一个语言要称为面向对象语言必须支持几个主要面向对象的概念。根据支持程度的不同,通常所说的面向对象语言可以分成两类:基于对象的语言,面向对象的语言。基于对象的语言仅支持类和对象,而面向对象的语言支持的概念包括:类与对象、继承、多态。举例来说,Ada就是一个典型的基于对象的语言,因为它不支持继承、多态,此外其他基于对象的语言还有Alphard、CLU、Euclid、Modula。面向对象的语言中一部分是新发明的语言,如Smalltalk、Java,这些语言本身往往吸取了其他语言的精华,而又尽量剔除他们的不足,因此面向对象的特征特别明显,充满了蓬勃的生机;另外一些则是对现有的语言进行改造,增加面向对象的特征演化而来的。如由Pascal发展而来的ObjectPascal,由C发展而来的Objective-C,C++,由Ada发展而来的Ada95等,这些语言保留着对原有语言的兼容,并不是纯粹的面向对象语言,但由于其前身往往是有一定影响的语言,因此这些语言依然宝刀不老,在程序设计语言中占有十分重要的地位。C++语言及环境中的OOP有五个最基本概念,这五个基本概念术语是构成整个C++面向对象方法与技术的柱石。它们是:a.对象(Object)b.消息(Message)c.方法(Method)d.类(Class)e.继承(Inheritence)下面我们将分别介绍它们的含义、组成和性质。1.对象第3章面向对象程序设计·23·什么是对象?对象是私有数据及可以对这些数据施加的操作结合在一起所构成的独立实体。即一个对象基本上包括两个主要部分:记载对象内部状态的数据和表现对象活动与功能的程序。从传统的SP观点来看,数据和处理它们的代码是两个不同的独立实体,它们之间的正确联系、选择和匹配需要应用系统的设计者时刻考虑。而OOP中,一个对象则是由私有数据和其上的一组操作代码组成的一个统一体。请看如下示意图:对象的动作取决于发送给该对象的消息表达式,消息告诉对象要求完成的功能,并激活该功能,这意味着对象具有自动“知道”如何完成相应操作代码的“智能”选择机制,正是这一机制把SP中应用系统程序员作出的选择操作数据与相应操作函数代码匹配的负担转移给了系统设计者。上述所谓的“智能化”的选择机制并不神秘,只不过是在对象的操作(过程或函数)表中对消息操作名进行按名搜索而已,对应C++来说,执行一个消息表达式就是触发选择机制在相应对象的调度表(内存控制块)中进行搜索,找到后便转向对应于该消息的成员函数代码中运行。事实上,除了上述选择匹配机制是新东西外,下面这些术语的含义和传统的SP相应名词及说明是相以对应的:对象——内存中的数据块对象标识符——指向上述数据的指针向对象发送消息——使成员函数作用于数据在OOP中,数据和代码是紧密结合在一起的计算机中的一内存分块。但局部于该对象中的数据只可以由对象中的代码块(成员函数)来访问,即数据是对象私有的(受保护的),不能被其它对象影响和修改。简单地说,一个对象从不关心其它对象的内部细节,而只关心它自己,对象之间的通讯只是以“做什么”的消息发送为契机,并且认为接受消息的对象是知道如何去做的。对象可以非常简单,也可以十分复杂。通常复杂对象由简单的对象层层嵌套组合而成。今后我们将从C++程序实例中看到,对象形式上只是系统程序员、应用程序员或用户定义的“类”这种数据结构类型的变量,当我们定义一个对象,就已创造出了一种新的抽象数据类型。对象可以说是构成和支撑整个OOP最重要的细胞与基石。除了上述基本组成、关系和机理特性外,对象还有以下性质和优点:a.模块独立性。逻辑上看,一个对象是独立存在的模块,从外部看这模块