荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: gybeango (Heymo), 信区: Program
标  题: OOP技术比较:java ,c++,object pascal
发信站: 荔园晨风BBS站 (Mon Apr  7 18:39:17 2003), 站内信件

本文将主要涉及三种面向对象语言:Internet上最流行的语言Java,最常见的OOP
语言C+
+,以及Borland公司用于他们的集成开发环境Delphi中的Object Pascal。这三种
语言具
有很多相同点。本文将从多个技术角度对这三种语言进行深入研究,并逐一比较。
至于
哪一种语言最优秀,我不想做过多的评论,这在很大程度上取决于你究竟要做什么

本文假定你基本掌握了所涉及的三种语言中的一种,或者至少大体上对OOP概念有
一定的
了解。我将会描述一些重要的语言特性,然后我会对三种语言的实现作一个比较。
我不
打算举实际的例子,我并不是要教授OOP,只是比较这些语言。

OOP关键特性
面向对象程序设计(OOP)并不是一种新的程序设计技术。它最早可以上溯到
Simula-67
,虽然它的第一个真正完整的实现是Simula-80。在80年代下半期,OOP变得流行起
来,
并且出现了许多支持OOP的语言,比如C++,Objective-C(另一种C语言扩展),
Object
PAscal和Turbo Pascal,CLOS(Lisp的面向对象扩展),Eiffel,Ada(其最新的
版本)
,以及最近的Java。本文将集中讨论C++、Object Pascal和Java,并有限的设计其
它OOP
语言。
OOP的关键特性是广为人知的,在继续下面的内容之前,我将简单的重复一下,以
便你再
熟悉一下这些通用技术。
·第一个关键特性是定义了类,封装了表现和操作的抽象数据类型。在OOP语言中
,类是
模块、封装和数据抽象的基础。
·第二个关键特性是继承,从已存在的类型中继承元素(表现和方法),改变或扩
展旧
类型的方法。
·第三个关键技术被称为多态性,它允许使用类似的方法操作不同类型的对象(通
常是
子类对象)。它使得类的可用性进一步提高,程序也因此更容易维护和扩展。
一种语言如果是面向对象的,必须具有类、继承和多态这几个特性(仅支持类而不
支持
继承和多态的语言,通常被称为基于对象的)。不同的OOP语言可能会使用完全不
同的方
法实现以上几个特性。我们可以通过比较类型检查机制、对不同程序设计模型的支
持以
及所支持的对象模型来区别不同的OOP语言。下面我将深入语言特性的细节。

编译期类型检查 vs. 运行期类型检查
类型的强壮性是评价程序设计语言的重要标准。涉及到类型检查的内容包括对已存
在的
方法的调用,方法的参数的类型,数组边界的检查,等等。
C++、Java和Object Pascal多或多或少的支持编译期类型检查,其中,C++的类型
检查最
弱,而Java的最强。原因是,C++保留了对C语言的支持,而C语言虽然支持编译期
类型检
查,却极其微弱。例如,C和C++认为所有数字类型都是兼容的(虽然向整型变量赋
浮点
数值时编译器会报警)。在Object Pascal和Java语言中,布尔值与整型数值不同
,而字
符类型则是另一个完全不兼容的类型。
虽然Java虚拟机在运行期“翻译”比特码,但并不表示它放弃了编译期类型检查。
相反
,在Java中类型检查进行的相当彻底。另外一些OOP语言,例如Smalltalk和CLOS,
则在
运行期进行类型检查。

混合OOP语言 vs. 纯OOP语言
另一个区别存在于纯的和混合的OOP语言之间。纯OOP语言只允许应用一种程序设计
模型
:OOP。你可以声明类和方法,但不能使用老式的普通函数、过程和全局变量。
在以上三种语言中,只有Java是纯OOP语言(Eiffel和Smalltalk也是),初看上去
纯OOP
是个很好的主意,然而,你最终还是会使用许多静态方法和静态数据。除了语法更
复杂
,这与使用全局函数和数据没有任何区别。我个人的观点是,纯OOP语言对于OOP的
初学
者非常有帮助,因为他将不得不使用(并学习)面向对象程序设计模型。另一方面
,C++
和Object Pascal都是典型的混合语言,他们允许程序员使用传统的C或Pascal程序
设计
方法。
要注意的是,Smalltalk大大扩展了纯面向对象的概念。在Smalltalk中,所有预定
义数
据类型,例如整型、字符型,甚至整个语言架构(例如循环指令)都是以对象封装
的。
这完全是出于对纯理论的兴趣,因为这样极大的降低了程序的执行效率。Java没有
做得
如此绝对,它允许使用传统的,非面向对象的数据类型(虽然它提供了对传统类型
的类
封装)。

普通对象模型 vs. 对象引用模型
OOP语言之间存在的第三个主要区别在于它们的对象模型。一些比较传统的OOP语言
允许
程序员在栈、堆和静态存储区中创建对象。在这些语言中,一个类的变量(实例)
对应
于内存中的一个对象。C++就是这样工作的。
之后的OOP语言倾向于使用另一种模型,称为对象引用模型。在这个模型中,每个
对象都
动态的创建于堆中,一个类的变量实际上是一个指向内存中的对象的引用或句柄(
技术
上类似于指针的某种东西)。Java和Object Pascal都采用了这种引用模型。我们
很快就
会看到,采用这种模型你必须记得为对象分配内存。

类、对象和引用
·特性描述:在介绍了以上内容后,我们进入对OOP语言的讨论。最好的起点是类
和对象
。我希望每个人都清楚的明白这两个名词的区别,简言之,一个类是一种数据类型
,而
一个对象则是某个类的实例。现在我们来看看如何在基于不同对象模型的OOP语言
中使用
对象。
·C++:在C++中,假设有一个类MyClass,这个类有一个方法MyMethod,我们可以
写出如
下代码:

  MyClass Obj;
  Obj.MyMethod;

这样就创建了一个名为Obj的MyClass类。通常C++会在栈中为这个对象分配内存空
间。现
在就可以像第二行代码那样使用对象了。

·Java:在Java中,类似的语句只为指向对象的句柄分配内存,而不是为对象本身


  MyClass Obj;
  Obj = new MyClass();
  Obj.MyMethod();

在你使用对象之前,必须使用“new”为对象分配内存。当然,最好在同一条语句
中声明
并初始化对象,以避免使用未被初始化的对象句柄:

  MyClass Obj = new MyClass();
  Obj.MyMethod();

·OP:Object Pascal采用大致相同的方法,但是必须在不同的语句中声明和初始
化对象


  var
    Obj: MyClass;
  begin
    Obj := MyClass.Create;
    Obj.MyMethod;

·注意:虽然对象引用模型似乎需要程序员写更多的代码,但要知道,在C++中经
常需要
使用对象的指针和引用(例如只有使用指针或引用,才能获得多态性能)。而在对
象引
用模型中,指针被默认使用,但却被巧妙的隐藏起来。特别是Java中并没有正式的
指针
,而事实上,指针无处不在。只不过程序员不能直接控制这些指针,但也因此他们
不会
随机访问内存地址,从而使程序更加安全。

回收
·特性描述:一旦你创建并使用了一个对象,就需要销毁它,以避免浪费内存资源


·C++:在C++中销毁一个储存在栈中的对象是十分容易的。另一方面,要销毁动态
创建
的对象就困难多了。有很多解决办法,例如引用计数和智能指针,但是这样增加了
复杂
程度。C++程序员的第一印象是使用引用对象模型来解决问题实在是太糟了。

·Java:对于Java来说,这是小事一桩,因为虚拟机会在后台运行碎片收集程序。
这使
得程序员轻松不少。但在另一方面,这也影响了应用程序的执行效率。如果没有编
写析
构器,可能会在清除代码执行时导致一个逻辑错误。

·OP:在Object Pascal中,没有类似的碎片收集机制。但是Delphi组件支持一种
新概念
,属主对象。属主对象将对所有下属组件的销毁负责。这就使对象销毁变得简单明
了。

定义新的类
·特性描述:我们已经了解了如何创建已存在的类的实例(对象),我们新的议题
是类
的定义。简单说来,一个类是一个方法的集合,而方法是定义在一些局部数据上的
操作


·C++:下面是一个简单类的C++定义:

  class Date {
    private:
      int dd;
      int mm;
      int yy;
    public:
      void Init(int d, int m, int y);
      int Day();
      int Month();
      int Year();
  };

下面是其中一个方法的定义:
  void Date::Init(int d, int m, int y)
  {
    dd = d;
    mm = m;
    yy = y;
  }

·Java:Java的语法与C++语法类似:
  class Date {
    int dd = 1;
    int mm = 1;
    int yy = 1;
    publlic void Init(int d, int m, int y) {
      dd = d; mm = m; yy = y; }
    public int Day () { return dd; }
    public int Month () { return mm; }
    public int Year () { return yy; }
  }

两者之间最大的不同在于Java的方法代码在声明的同时就定义了(与C++不同,这
并不表
示这些函数是内联函数),并且可以同时初始化类的数据成员。事实上,如果你没
有初
始化这些数据成员,Java会将所有数据成员初始化为默认值。

·OP:在Object Pascal的类声明语法更接近C++语法,但是仍有很多区别:

  type
    Date = class
    private
      dd, mm, yy: Integer;
    public
      procedure Init (d, m, y: Integer);
      function Month: Integer;
      function Day: Integer;
      function Year: Integer;
    end;

  procedure Date.Init (d, m, y: Integer);
  begin
    dd := d;
    mm := m;
    yy := y;
  end;

  function Date.Day: Integer;
  begin
    Result := dd;
  end;

你可能注意到一些语法上的区别:定义方法使用两个不同的关键字function和
procedure
,没有参数的方法不使用圆括号,方法在类定义中声明,之后再作定义(就像C++
中经常
遇到的情况一样)。注意,Pascal使用点运算符,而C++使用作用域操作符(::)


·注意:访问当前对象。OOP语言的方法与全局函数不同,它包含了一个隐藏参数
——一
个指向当前被操作对象的指针或引用。在不同的语言中,这个参数的名字不同,在
C++和
Java中是this,在Object Pascal中是self。

构造函数(constructor)
·特性描述:上文所述的类实在太简单了。为了解决对象初始化的问题,我们要为
类增
加一个构造函数,这也是改进类所需迈出的第一步。

·C++:在C++以及Java中,构造函数和类具有相同的名字。如果你没有定义构造函
数,
编译器会自动为类添加一个默认构造函数。在这两种语言中,你的类可以具有多个
构造
函数,这要感谢“方法重载”。

·Java:在Java中,虽然构造函数也被称为初始化函数(initializer),但与
C++的构
造函数在使用上没有什么区别。需要注意的是,Java虚拟机负责创建对象,而构造
函数
只对创建的对象进行初始化(Object Pascal也有类似的情况)。

·OP:在Object Pascal中,构造函数以一个特殊的关键字——constructor声明。
在OP
中没有方法重载(?,没有吗?——译者),不过因为构造函数(在Delphi的书中
通常
成为构造器——译者)的名字可以任意指定,所以你可以提供几个名字不同的构造
函数
。OP中每个类都有默认的构造函数“Create”,除非你用名字相同而参数不同的构
造函
数将其覆盖。这个构造函数继承自一个通用基类,下面我们会提到。

析构函数和finalize()
·特性描述:析构函数扮演了构造函数反面的角色,通常在对象销毁时被调用。如
果说
大多数类都需要构造函数,那么只有很少的类需要析构函数。一个析构函数的基本
功能
就是释放构造函数(以及对象生存期中的其它方法)分配的资源。这些资源包括内
存、
文件、数据库表、Windows句柄,等等。

·C++:C++的析构函数在对象超出作用域时,或者删除动态创建对象时自动被调用
。每
个类只能由一个析构函数。

·OP:Object Pascal的析构函数与C++的析构函数类似。Object Pascal使用标准
虚拟析
构函数,称为“Destroy”。析构函数通过标准“Free”方法调用。因为所有对象
都是动
态创建的,所以你或者对象的属主必须调用对象的析构函数,以释放资源。理论上
你可
以定义多个析构函数,不过只有你手动调用析构函数才有些价值(没有什么是自动
完成
的)。

·Java:Java没有析构函数。没有引用的对象将被碎片回收程序在后台销毁。在销
毁对
象之前,碎片回收程序调用finalize()方法。但是,并没有什么保证这个函数真正
被调
用(至少在Java 1.0中时是这样)。因此,如果你需要释放资源,你就要定义一个
方法
,并保证它被调用。

类封装(Private和Public)
·特性描述:这三种语言提供了相同的三种访问限定符来提供不同级别的类封装:
publi
c,protected和private。public意味着对于任何类都是可见的,protected意味着
对于
派生类可见,private意味着没有外部可见性。但是三种语言的实现细节并不相同


·C++:在C++中,你可以使用friend关键字跳出类封装。由class关键字声明的类
默认可
见性是private,由struct关键字声明的类默认可见性是public。

·OP:在Object Pascal中,private和protected关键字只对在不同单元中的类有
作用。
在同一单元(源代码文件)声明的类彼此之间可以自由访问。Delphi还有两个特殊
的访
问限定符:published和automated。published将为类的成员建立RTTI(运行期类
型信息
),automated用于OLE自动化接口(已废弃——译者)。

·Java:在Java中,一个语法上的区别是每一个类成员都要用访问限定符声明。另
一个
实质上的区别是,Java中类成员默认访问限定符是friendly,因此对同一个包(源
代码
文件,类似于OP的单元)中的所有类都是可见的。同样,protected关键字表示类
成员对
派生类可见,同时也对同一个包中的其它类可见,而private protected才对应于
C++中
的protected。

文件、单元和包
·特性描述:这三种语言的一个重要区别是对源代码文件的组织管理。它们都使用
文件
作为储存源代码的标准机构(与其它OOP语言如Smalltalk不同),不同的是C++的
编译器
并不真正了解文件,而OP和Java则不同,它们使用模块概念来管理文件,虽然各自
的名
字不太一样。

·C++:在C++中,程序员们一般把类定义放在头文件中,而把方法实现放入独立的
代码
文件。通常这两个文件会具有相同的文件名和不同的扩展名。一个编译单元应该包
括它
自己的声明文件及其代码所涉及的类及函数的声明文件。但这仅仅是惯例,编译器
并不
强迫这样做。链接器将不得不做更多的工作,因为编译器无法预料一个方法是否在
某个
模块中被定义。

·OP:在Object Pascal中,源代码文件被称为单元(unit)。单元被分为接口(
interf
ace)和实现(implementation)两部分。接口部分包含了类的定义(包括方法的
声明)
,实现部分则包含了声明于接口部分的方法的定义。在接口中编写执行代码是非法
的。
你可以使用uses子句包含其它文件,以便引用其中声明的类、方法等等。下面的代
码包
含了一些编译单元的接口:

uses
  Windows, Form, MyFile;

·Java:在Java中,每个源代码文件,或者说编译单元之间是完全独立的。你可以
把一
组编译单元作为一个包的一部分。与其它两种语言不同,在声明类的同时要编写方
法实
现的代码。当使用import子句包含一个文件时,编译器只读入它的public声明,而
不是
所有的代码:

import where.myclass;
import where.* // all the classes

·注意:关于被称为名字空间的模块。另一个关键性的区别是Java和OP的编译器可
以读
入一个已编译文件,并从中提取它的定义,就像你从已编译代码中提取头文件一样
。另
一方面,C++语言引用名字空间(namespace)来弥补没有模块结构的不足。在
Java和OP
中,事实上,通常以模块的名字为前缀来解决名字之间的冲突。使用名字空间也可
以达
到同样的效果,不过它是内建在语言中的。

类/静态方法和数据成员
·特性描述:通常OOP语言允许某些方法和数据成员与整个类相关,而不是对象个
体。一
般的类方法可以通过类的单个对象或类调用。类数据成员是被所有对象共享的数据
成员
,而不是为每个对象单独创立。

·C++:在C++中,类方法和类数据成员以static关键字声明。类数据成员必须使用
一个
特殊的声明来初始化,这是缺少模块结构的不足之一。

·OP:OP中只有类方法,使用class关键字声明。而定义于同一单元中的私有全局
变量可
以发挥类数据成员的作用。

·Java:Java使用和C++相同的关键字static。静态方法经常被使用(甚至有些过
分),
这是因为在Java中没有全局函数。静态数据成员可以直接在类声明中初始化。

类和继承
·特性描述:类的继承是OOP的根基之一。它可以用来做一般化表述和特殊化表述
。关于
继承的基础思想是通过修改或扩展现存的类型建立新的类型,换句话说,一个派生
类具
有基类的所有数据成员和方法,并添加了新的数据成员和方法,还有可能修改某些
以存
在的方法。不同的OOP语言用不同的名词描述这种机制(derivation,
inheritance,sub
classing)、被继承的类(基类,父类,超类)和继承的类(派生类,子类,次类
)。

·C++:C++使用public、protected和private关键字定义继承的方式,改变继承的
方法
和数据成员的访问限定类型。虽然public继承最常被使用,但在C++中默认的是
private
继承。C++是这三种语言中唯一允许多重继承的语言,以后我们还会提到。下面是
一个例
子:

class Dog: public Animal {
...
};

·OP:Object Pascal使用一个特殊的语法表述继承,而不是使用关键字,方法是
将基类
名放入括号中,添加到类声明中。OP只支持C++中所谓public的继承。OP类具有一
个通用
基类,以后我们会见到。

type
  Dog = class (Animal)
    ...
  end;

·Java:Java使用extends关键字来表述唯一一种继承类型,对应于C++中的
public继承
。Java不支持多重继承。Java类同样具有一个通用基类。

class Dog extends Animal {
...
}

·注意:关于基类的构造函数和初始化。在C++和Java中,基类的构造函数具有很
复杂的
结构。在OP中,初始化基类则是程序员的责任。这个主题比较复杂,所以我不打算
进一
步讲述。我会把注意力集中在通用基类、基类访问、多重继承、接口、后期绑定以
及其
它相关的内容。

所有类的祖先
·特性描述:在一些OOP语言中,所有类都直接或间接的派生自某个特定的基类。
这个类
(通常被称为Object或其它类似的名字)具有所有类共有的基本功能。事实上,所
有类
都继承自这个基类。因为最初在Smalltalk中便是如此设计的,所以大多数OOP语言
采用
了这个概念。

·C++:虽然在C++中没有这个概念,但许多应用程序框架引入了通用基类的概念。
MFC是
个很好的例子,它有一个CObject类。事实上,最初这是十分意义的,因为语言不
具有模
板特性(以及多重继承特性)。

·OP:每个类都自动的继承自TObject类。因为OP不支持多重继承,所以所有的类
构成了
一个巨大的派生树。TObject类可以处理RTTI,同时具有其它一些能力。

·Java:如同OP一样,所有的类继承自Object类。这个基类也具有一些有限的功能


访问基类的方法
·特性描述:当编写一个类方法或者重载一个基类方法时,你经常需要引用基类的
方法
。而如果方法在派生类中重新被定义,那么使用方法的名字将调用新方法。OOP语
言使用
不同的技术或关键字解决访问基类方法的问题。

·C++:在C++中可以使用范围操作符(::)引用一个特定的类。你不仅可以访问基
类,
甚至可以访问继承链中更高层的类。

·OP:Object Pascal使用一个特殊的关键字完成同样的工作:inherited。在关键
字后
可以加上需要调用的基类方法的名称,或者(在某些情况下),简单的使用这个关
键字
来访问对应的基类方法。

·Java:Java中使用super关键字完成类似的工作。在Java和OP中,你无法访问更
高一级
的基类。看起来这似乎限制了什么,但是这样可以通过添加中间类来扩展继承链。
同时
,如果你不需要基类的功能,你也许可以不从这个基类派生你的新类。

子类兼容性
·特性描述:并不是所有OOP语言都是强类型的,就像我开始提到的,但是这里我
们涉及
的三种语言都是。这意味着不同类的对象之间是不兼容的。只有一个例外,就是派
生类
的对象与基类是兼容的(注意:反过来不成立)。

·C++:在C++中,子类兼容性规则只适用于指针和引用,对普通对象则不适用。事
实上
,不同的对象在所占用的内存不同,所以你不能将相同的内存分配给不同的对象。


·OP:子类兼容性适用于所有对象,因为OP采用了对象参考模型。此外,所有对象
都与T
Object类型兼容。

·Java:Java的情况与OP完全相同。

·注意:多态性。如同下一节将要描述的,子类兼容性对于实现后期绑定和多态性
是十
分重要的。

后期绑定(及多态性)
·特性描述:当继承链中不同的类分别重新定义了它们基类的方法,那么如果能够
通过
一个兼容这些类的对象(感谢子类兼容性)调用合适的类的方法,将是十分有用的
。要
完成这个工作,编译器需要支持后期绑定,它将不产生一个特定的函数调用,而是
在运
行期决定了对象的真正类型后,才进行函数调用。

·C++:在C++中,后期绑定只应用于虚拟方法(在调用速度上会有所减慢)。一个
在基
类中定义的虚拟方法将在它被重新定义时保持这种特性(当然方法的声明必须完全
匹配
)。一般情况,非虚拟方法并不允许后期绑定。

·OP:在Object Pascal中,后期绑定通过关键字virtual或dynamic引入(这两个
关键字
的区别仅在于技术实现的不同)。在派生类重新定义方法时,应使用override关键
字(
这样就强迫编译器检查方法声明是否匹配)。这是OP中特有的,它允许在基类做更
多的
改动。

·Java:在Java中,所有的方法都使用后期绑定,除非你使用final关键字。
final方法
不能被重新定义,在调用速度上更快。在Java中正确的方法名称对于多态性的实现
是非
常重要的。Java中默认后期绑定和C++中默认前期绑定这一事实表明了这两种语言
不同的
针对性:C++有时会牺牲OOP模型以获取性能的提升。

·注意:构造函数和析构函数的后期绑定。与其它两种语言相反,Object Pascal
允许定
义虚拟构造函数。而这三种语言都支持虚拟析构函数。

抽象方法和抽象类
·特性描述:当建立一个复杂的继承链时,为了实现多态性,经常需要为更高级的
类引
入一些方法,虽然这些方法未必是为这个类抽象概念而定义的。除了使用空方法定
义,
许多OOP语言实现了一种特殊的机制:定义抽象方法。所谓抽象方法就是没有实现
的方法
。具有一个或多个抽象方法的类称为抽象类。

·C++:在C++中,抽象方法被称为纯虚函数,通过在方法定义后添加所谓虚定义符
(=0
)可以获得一个抽象方法。抽象类就是具有(或继承了)一个或多个抽象方法的类
。不
能创建抽象类对象。

·OP:Object Pascal使用abstract关键字声明抽象方法。同样,抽象类就是具有
或继承
了抽象方法的类,但是你可以创建抽象类的实例(虽然编译器会产生一个警告信息
)。
这就隐含了调用抽象方法的危险,在运行期,这样会产生一个运行期错误,并会终
止程
序的运行。

·Java:在Java中,抽象方法和抽象类都用abstract关键字声明(事实上Java中的
抽象
类必须具有抽象方法,好像有一点多余)。同样,派生类如果没有重新定义所有的
抽象
方法,必须使用abstract关键字定义为抽象类。不能创建抽象类的实例。

多重继承和接口
·特性描述:一些OOP语言允许从多个基类派生新类。另一些语言只允许从一个类
中派生
新类,但是可以从多个接口(或者纯抽象类,只由纯虚函数构成的类)派生新类。


·C++:C++是三种语言中唯一支持多重继承的。一些程序员认为这是一件好事,另
一些
程序员认为这是一件坏事,我不想过多的讨论这个问题。多重继承产生了很多新概
念,
比如说虚基类,虽然功能强大,但并不好掌握。C++没有接口的概念,虽然它与多
重继承
的纯抽象类概念接近(接口可以看作多重继承的子集)。

·Java:Java,以及Object Pascal,都不支持多重继承,但是完全支持接口。接
口的方
法支持多态性,并且当需要一个接口对象时,可以通过一个对象实现接口。一个类
只能
继承自一个基类,但可以implement(关键字)多个接口。Java的接口与COM模型非
常吻
合,虽然没有预先的考虑。举个例子:

public interface CanFly {
public void Fly();
}
public class Bat extends Animal implements CanFly {
public void Fly( ) { // the bat flies... }
}

·OP:Delphi 3在Object Pascal中引入了类似Java的接口,这些接口非常吻合
COM(虽
然技术上经常在非COM程序中使用)。接口构造了一个与类独立的继承链,但是与
Java一
样,一个类可以继承自唯一的基类并实现多个接口。将类的方法映射为类实现的接
口的
方法是Object Pascal语言中令人迷惑的几个问题中的一个。

RTTI
·特性描述:在强类型OOP语言中,编译器完成所有类型检查的工作,所以很少需
要运行
程序保存类型的信息。然而,某些情况下需要某些类型信息。因此,这三种OOP语
言都或
多或少的支持运行期类型识别/信息(RTTI)。

·C++:最初的C++语言不支持RTTI。后来通过dynamic_cast的方式提供了部分的类
型信
息。你可以查询一个对象的类型,也可以检查两个对象是否具有相同的类型。

·OP:Object Pascal以及它的可视开发环境支持也需要大量的RTTI。不仅可以进
行类型
检查(使用is和as操作符),类也为它的published成员生成大量的RTTI。事实上
这个关
键字负责部分RTTI的生成。属性、流结构(窗体文件以及始于对象观察器的
Delphi环境
很大程度上依赖于类的RTTI。TObject类具有ClassName和ClassType方法。
ClassType方
法返回一个类类型变量——一个特殊类参考类型的实例(并不是类本身)。

·Java:和Object Pascal一样,Java中也有一个基类用于跟踪类型信息。Object
类的ge
tClass()方法会返回一个元类(一个用于描述类的类型的对象),你也可以使用
getName
()函数获得一个类名字符串。你还可以使用instanceof操作符。Java 1.0不支持更
多内
容的RTTI,但在未来的版本中可能会改变,以适应可视环境和组件的开发(所谓
Java
Beans)。

·例子:

// C++
Dog* MyDog = dynamic_cast <Dog*> (myAnimal);
// Java
Dog MyDog = (Dog) myAnimal;
// Object Pascal
Dog myDog := myAnimal as Dog;

异常处理
·特性描述:异常处理构想的出发点是简化程序的错误处理代码,提供标准内建机
制,
从而使程序更加健壮。异常处理的内容很多,这里我只是简述一些关键的要素和区
别。

·C++:C++使用throw关键字来产生一个异常,用try关键字标志被保护的程序块,
用cat
ch关键字标志异常处理程序代码。异常是一些特殊类的对象,在这三种语言中都构
成了
各自的继承链。C++会对所有栈中的对象进行栈展开和销毁(调用析构函数)。

·OP:Object Pascal使用与C++类似的关键字raise,try和except,并且具有类似
的功
能。唯一真正的区别是因为没有对象会被创建于栈中,所以不会发生栈展开。另外
,你
可以使用一个finally关键字,标志那些无论是否产生异常都被执行的代码。在
Delphi中
,异常类全部派生自Exception。

·Java:Java使用和C++相同的关键字,但是其行为却更接近于Object Pascal,包
括使
用finally关键字。所有采用对象引用模型的语言基本都是如此。碎片回收程序的
存在限
制了finally关键字对类的应用,这些类不仅占用了内存资源。Java认为所有能产
生异常
的函数都具有一个正确的异常子句,这个子句告诉Java哪些异常可能会被产生。这
个假
设十分严格,并由编译器进行检查。这是一个非常有用的技术,即使这意味着程序
员要
做更多的工作。Java中的异常类必须派生自Throwable类。

模板(通用程序设计)
·特性描述:在不指定某些数据类型的情况下编写函数和类的技术,称为通用程序
设计
。在函数或类被使用的时候,特定的数据类型会代替函数或类中的未指定部分。所
有情
况都在编译器的监管之下,不会有任何问题遗留给运行期来决定。模板类的一个典
型的
例子就是容器类。

·C++:这三种语言中只有C++具有通用类和函数,这些类和函数用Template关键字
表示
。C++标准包含了一个巨大的模板类库,称为STL,用于支持一些特殊而有用的程序
设计
功能。

·OP:Object Pascal不支持模板。容器类通常被创建为TObject类对象的容器。

·Java:Java同样不支持模板。你可以使用对象容器,或采用其它类似的方法。

其它特殊特性
·特性描述:以下是其它一些我谈及的特性,它们不是基础特性,而且仅为一种语
言所
特有。

·C++:我已经提到了多重继承、虚基类和模板。还有一些另外两种语言所不具有
的特性
。C++支持操作符重载,而Java中支持方法重载。C++还允许程序员重载全局函数。
你甚
至可以重载类运算符,编写可能会在后台被调用的类型转换方法。C++的对象模型
需要拷
贝构造函数和赋值运算符重载,而其它两种语言则不需要,因为它们基于对象引用
模型


·Java:只有Java在语言中支持多线程。对象和方法支持同步机制(使用
synchronized
关键字):同一个类的两个synchronized方法不能同时运行。要创建一个新的线程
只需
从Thread类中派生新类,并覆盖run()方法。另一个方法是实现Runnable接口(这
是建立
多线程applet的常用方法)。我们已经讨论过了碎片回收程序。Java的另一个关键
特性
是代码兼容性,但是这并不是严格的与语言相关的。

·OP:Object Pascal的一些特性包括类引用,便利的方法指针(这是事件模型的
基础)
,特别是属性。属性用来隐藏对数据成员的访问,这些访问大多是通过方法进行的
。属
性可以直接映射为对数据成员的读写操作,也可以映射为访问函数。即使改变了访
问数
据成员的方式,也不需要改变调用的代码(虽然需要重新编译),这使得属性称为
了一
个强大的封装特性。Java也将在1.1版中加入这个特性,以支持Java Beans。

标准
·特性描述:每个语言都需要有人建立一个标准,并检查是否所有的实现都符合这
个标
准。

·C++:ANSI/ISO C++标准委员会已经完成了标准化工作。大多数编译器编写者都
努力遵
守这个标准,虽然还有很多的差异存在。理论上的发展已基本停止。但在实现上,
新的B
orland C++ Builder虽然并不很成熟,但使很多人认识到C++迫切的需要一个可视
开发环
境。同时,广为流行的Visual C++将C++向另一个方向发展起来,例如,大量使用
宏。我
的意见是,每个语言都有它的开发模型,在不适于某种语言的环境下强行使用这种
语言
是毫无意义的。

·OP:Object Pascal是一个私有语言,所以没有标准。Borland已经授权给一些
OS/2编
译器开发商,但是没有什么效果。在每一个新版本的Delphi中,Borland都扩展了
这种语
言。

·Java:Java也是私有语言,并且拥有一个同名的商标。但是Sun更愿意授权给其
它编译
器开发商。Sun自己控制着这种语言,并且好像并不想为其建立一个官方的标准,
至少目
前如此。Sun也在极力避免不遵守标准的虚拟机被开发出来。

结论:语言和开发环境
就像我上面提到过的,虽然我尽力做到只比较语言的语法语义特性,但在适当的环
境中
考察它们是很重要的。这些语言为不同的目标开发出来,是为了以不同的途径解决
不同
的问题的,并在不同的开发环境中被应用。虽然语言和它们的开发环境体现了彼此
的一
些特性,但它们是为了满足不同的需要而建立的,就像我们在对比这些特性时看到
的那
样。C++的目标是强大的功能和控制能力,代价是复杂性提高;Delphi的目标是在
不损失
太多功能的情况下,尽可能简单以及可视化编程和同Windows紧密结合;Java的目
标是兼
容性和分布式应用,为此不惜牺牲一些运行速度。
决定这三种语言命运的并不是我这篇文章中所涉及的那些语言特性。Borland的财
政状况
,Microsoft对操作系统的控制,Sun在Internet世界的声望(许多人认为的反微软
),W
eb浏览器和Win32 API的前景,ActiveX(以及Delphi的ActiveForms)将扮演的角
色,这
些都是影响你选择的因素(往往超过了技术因素)。例如那个非常优秀的语言
Eiffel—
是毫无意义的。

·OP:Object Pascal是一个私有语言,所以没有标准。Borland已经授权给一些
OS/2编
译器开发商,但是没有什么效果。在每一个新版本的Delphi中,Borland都扩展了
这种语
言。

·Java:Java也是私有语言,并且拥有一个同名的商标。但是Sun更愿意授权给其
它编译
器开发商。Sun自己控制着这种语言,并且好像并不想为其建立一个官方的标准,
至少目
前如此。Sun也在极力避免不遵守标准的虚拟机被开发出来。

结论:语言和开发环境
就像我上面提到过的,虽然我尽力做到只比较语言的语法语义特性,但在适当的环
境中
考察它们是很重要的。这些语言为不同的目标开发出来,是为了以不同的途径解决
不同
的问题的,并在不同的开发环境中被应用。虽然语言和它们的开发环境体现了彼此
的一
些特性,但它们是为了满足不同的需要而建立的,就像我们在对比这些特性时看到
的那
样。C++的目标是强大的功能和控制能力,代价是复杂性提高;Delphi的目标是在
不损失
太多功能的情况下,尽可能简单以及可视化编程和同Windows紧密结合;Java的目
标是兼
容性和分布式应用,为此不惜牺牲一些运行速度。
决定这三种语言命运的并不是我这篇文章中所涉及的那些语言特性。Borland的财
政状况
,Microsoft对操作系统的控制,Sun在Internet世界的声望(许多人认为的反微软
),W
eb浏览器和Win32 API的前景,ActiveX(以及Delphi的ActiveForms)将扮演的角
色,这
些都是影响你选择的因素(往往超过了技术因素)。例如那个非常优秀的语言
Eiffel—
—Object Pascal和Java都从中吸取了很多灵感,没有抢到任何市场份额,虽然它
在全世
界的许多大学中都十分流行。
记住,“时髦”这个词已经在计算机世界占有了前所未有的地位。就像用户喜欢使
用今
年新版本的软件(这大概就是为什么操作系统都以年份命名),程序员们也喜欢用
最新
的程序设计语言,并希望第一个掌握它。我们可以说“Java并不是最新的OOP语言
”,在
未来的几年里,一些人会开发出更时髦的语言,而其他人则会蜂拥而上,全然忘记
了这
个世界上大多数程序员还在他们的键盘上敲打着传统的Cobol语句!

作者简介
Marco Cantu撰写过多本涉及以上谈及的两到三种语言的书,如Object Pascal and
 C++
,并在美国和其它一些国家发行。他为多家杂志撰写稿件,并在他的公司
WinTech
Italia中进行多项OOP语言和Windows程序设计的培训。他喜欢在国际性会议中发表
讲话
。你可以在以下网址找到他:www.macrocantu.com。

http://www.xuyiting.com
--

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.61]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店