第7章 对象
即使你没有面向对象编程(OOP)的详细知识,本章也将介绍每一个关键概念。如果你已经精通OOP,你可以相对快速地浏览材料,并将重点放在Object Pascal语言的细节上,与你可能已经掌握的其他语言进行比较。
Object Pascal
中的OOP支持与C#和Java等语言有很多相似之处,它也与C++和其他静态和强类型语言有一些相似之处。相反,动态语言倾向于提供对OOP的不同解释,因为它们以更松散和灵活的方式处理类型系统。
C#
和Object Pascal
之间许多概念有相似之处是由于这两种语言都是同一个设计师Anders Hejlsberg。Anders是Turbo Pascal
编译器的原作者,也是Delphi的Object Pascal
第一版的原作者,后来他跳槽到微软并设计了C#(以及最近的JavaScript
衍生物TypeScript
)。你可以在附录A中关于Object Pascal
语言历史的内容。
7.1 引入类和对象
在Object Pascal
和其他面向对象的编程语言中,经常使用类和对象这两个术语。 然而,由于它们经常被误用,让我们确保从一开始就对它们的定义达成共识:
- 类是一个用户定义的数据类型,定义了一种状态(或表示)和一些操作(或行为)。换句话说,一个类有一些内部数据和一些方法,以过程或函数的形式存在。类通常描述了许多相似对象的特征和行为,尽管也有专门用于单个对象的特殊类。
- 对象是类的一个实例,即由类定义的数据类型的变量。对象是实际存在的实体。程序运行时,对象占用一些内存来存储其内部表示。
- 对象和类的关系与其他变量与其数据类型之间的关系相同,不同之处在于对象变量有一个特殊的名称,即实例。
历史: 面向对象编程(OOP)术语可以追溯到最早采用这一模型的几种语言,如Smalltalk。然而,后来为了使用在过程性语言中的术语,最初的面向对象术语很大一部分而被取消。因此,尽管诸如类和对象之类的术语仍然常用,但您通常更常听到调用方法这一术语,而不是原始术语向接收者(对象)发送消息。关于OOP术语及其如何随时间演变的全面详细指南可能很有趣,但在这本书中需要太多篇幅。
7.1.1 类的定义
在Object Pascal
中,您可以使用以下语法定义新的类数据类型(TDate
),其中包含一些本地数据字段(Month、Day、Year)和一些方法(SetValue、LeapYear):
typeTDate = classFMonth, FDay, FYear: Integer;procedure SetValue(M, D, Y: Integer);function LeapYear: Boolean;end;
注解: 我们已经在记录中看到过类似的结构。就定义而言,记录与类相当相似。在内存管理和其他方面存在差异,本章后面将详细介绍。尽管如此,从历史上看,在
Object Pascal
中,这个语法首先用于类,然后被移植到记录。
Object Pascal
的惯例是使用字母 T 作为你编写的每个类名称的前缀,就像其他类型一样(事实上,T 代表 Type)。对编译器来说,T 只是一个字母,与其他字母无异。——但这是如此常见,遵循这个习惯会使您的代码更容易被其他程序员理解。
与其他语言不同,Object Pascal 中的类定义不包括方法的实际实现(或定义),而只包括方法的签名(或声明)。这使得类代码更加紧凑,可读性大大提高。
小贴士: 虽然看起来进入方法的实际实现要花费更多时间,但编辑器允许你使用 Shift+Up 和 Shift+Down 组合键从方法声明导航到方法实现,反之亦然。此外,在编写类定义后,还可以使用 “类完成”(Class Completion)(光标在类定义中时按 Ctrl+C 键)让编辑器生成方法定义的骨架。
此外,除了编写类的定义(包括字段和方法)外,您还可以编写一个声明。声明中只有类名,如:
typeTMyDate = class;
之所以要写这样的声明,是因为你可能需要让两个类互相引用。在 Object Pascal 中,一个符号只有在定义后才能使用。因此,要引用一个尚未定义的类,就需要声明。我写下面的代码片段只是为了向你展示语法,并不是说它有任何意义:
typeTHusband = class;TWife = classFHusband: THusband;end;THusband = classFWife: TWife;end;
您可能在实际代码中遇到类似的交叉引用,这就是为什么记住这种语法很重要的原因。 请注意,与方法一样,在单元中声明的类必须在稍后的同一单元中完全定义。