面向对象语言(Object-Oriented Language)是一类以对象作为基本程序结构单位的程序设计语言,指用于描述的设计是以对象为核心,而对象是程序运行时刻的基本成分。语言中提供了类、继承等成分。 面向对象语言借鉴了20世纪50年代的人工智能语言LISP,引入了动态绑定和交互式开发环境的思耄皇加?0年代的离散事件模拟语言SIMULA67,引入了类的要领和继承,成形于70年代的Smalltalk。面向对象语言的发展有两个方向:一种是纯面向对象语言,如Smalltalk、EIFFEL等;另一种是混合型面向对象语言,即在过程式语言及其它语言中加入类、继承等成分,如C++、Objective-C等。 面向对象语言刻画客观系统较为自然,便于软件扩充与复用。有4个主要特点: (1)识认性,系统中的基本构件可识认为一组可识别的离散对象;(2)类别性,系统具有相同数据结构与行为的所有对象可组成一类;(3)多态性,对象具有惟一的静态类型和多个可能的动态类型;(4)继承性,在基本层次关系的不同类中共享数据和操作。 其中,前三者为基础,继承是特色。四者(有时再加上动态绑定)结合使用,体现出面向对象语言的表达能力。 一般认为,较典型的面向对象语言有: SIMULA67,支持单继承和一定含义的多态和部分动态绑定;Smalltalk支持单继承、多态和动态绑定;EIFFEL,支持多继承、多态和动态绑定;C++,支持多继承、多态和部分动态绑定。 四种语言涉及概念的含义虽基本相同,但所用术语有别。 基于类的面向对象语言 基于类的面向对象语言是面向对象世界里的主流。它包括: Simula, 第一个面向对象语言 Smalltalk, 第一个支持动态类型的语言 C++, 它的大部分基于类的特性继承自Simula.等等等等。 与基于类的语言相对应的是基于对象的面向对象语言。这里“基于对象”的概念和把Visual Basic叫做基于对象的概念是不同的。这里的“基于对象”是指一个只以对象为中心,没有类的概念的语言,类似Python之类的语言。 现在,我们来介绍一下基于类的面向对象语言的一些共同特征。 1.类和对象 让我们先看一个类的定义: class cell is var contents: Integer :=0; method get(): Integer is return self.contents; end; method set(n:Integer) is self.contents := n; end; end; 一个类是用来描述所有属于这个类的对象的共同结构的。这个cell类表示的对象拥有一个叫做contents的整数属性(attribute),这个属性被初始化成0。它还描述了两个操作contents的方法。Get和set. 这两个方法的内容都是很直观的。Self变量表示这个对象自己。 对象的动态语义可以这样理解: 一个对象在内部被表示为一个指向一组属性的指针。任何对这个对象的操作都会经过这个指针操作对象的属性和方法。而当对象被赋值或被当作参数传递的时候,所传递的只是指针,这样一来,同一组属性就可以被共享。 (注, 有些语言如C++, 明确区分指向属性组的指针和属性组本身,而一些其它的语言则隐藏了这种区别) 对象可以用new从一个类中实例化。准确地说,new C分配了一组属性,并返回指向这组属性的指针。这组属性被赋予了初始值,并包括了类C所定义的方法的代码。 下面我们来考虑类型。对一个new C所生成的对象,我们把它的类型记为InstanceTypeOf(c). 一个例子是: var myCell: InstanceTypeOf(cell) := new cell; 这里,通过引入InstanceTypeOf(cell), 我们开始把class和type区分开来了。我们也可以把cell本身当作是类型,但接下来,你就会发现,那样做会导致混淆的。 2.方法解析(Method Lookup) 给出一个方法的调用o.m(……), 一个由各个语言自己实现的叫做方法解析的过程负责找到正确的方法的代码。(译者按:是不是想起了vtable了?)。 直观地看,方法的代码可以被嵌入各个单个对象中,而且,对于许多面向对象语言,对属性和方法的相似的语法,也确实给人这种印象。 不过,考虑到节省空间,很少有语言这样实现。比较普遍的方法是,语言会生成许多method suite, 而这些method suite可以被同一个类的对象们所共享。方法解析过程会延着对象内指向method suite的指针找到方法。 在考虑到继承的情况,方法解析会更加复杂化。Method suite也许会被组成一个树,而对一个方法的解析也许要查找一系列method suite. 而如果有多继承的话,method suite甚至可能组成有向图,或者是环。 方法解析可能发生在编译时,也可能发生在运行时。 在一些语言中,方法到底是嵌入对象中的,还是存在于method suite中这种细节,对程序员是无关紧要的。因为,所有能区分这两种模式的语言特性一般在基于类的面向对象语言中都不被支持。 比如说,方法并不能象属性一样从对象中取出来当作函数使用。方法也不能象属性一样在对象中被更新。(也就是说,你更新了一个对象的方法,而同一个类的其它对象的该方法保持不变。) 3. 子类和继承(Subclassing and Inheritance) 子类和一般的类一样,也是用来描述对象的结构的。但是,它是通过继承其它类的结构来渐进式地实现这个目的。 父类的属性会被隐式地复制到子类,子类也可以添加新的属性。在一些语言中,子类甚至可以override父类的属性(通过更改属性的类型来实现) 父类中的方法可以被复制到子类,也可以被子类override. 一个子类的代码的示例如下: subclass reCell of cell is var backup: Integer := 0; override set(n: Integer) is self.backup := self.contents; super.set(n); end; method restore() is self.contents := self.backup; end; end; 对有subclass的方法解析,根据语言是静态类型还是动态类型而有所不同。 在静态类型的语言(如C++, Java)里,父类,子类的method suite的拓扑结构在编译时就已经确定,所以可以把父类的method suite里的方法合并到子类的method suite中去,方法解析时就不用再搜索这个method suite的树或图了。(译者按:C++的vtable就是这种方法) 而对于动态类型的语言,(也就是说,父子类的关系是在运行时决定的),method suite就无法合并了。所以,方法解析时,就要沿着这个动态生成的树或有向图搜索直到找到合适的方法。而如果语言支持多继承,这个搜索就更复杂了。

评论