Delphi 对象模型学习笔记

2008-04-09 04:24:51来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折


标题:Delphi 对象模型学习笔记
关键词:Delphi 对象模型
作者:dREAMtHEATER
难度:普通[] 中等[x] 高级[]
http://dREAMtHEATER.yeah.net
E-Mail:NoteXPad@163.com
完成日期:2004年08月21日


摘要
Borland Object Pascal 对象模型(现在已经正是命名为 Delphi 语言)与其他 OOP 语言一样,都提供了一些基础服务: 如对象创建服务、对象释放服务、对象识别服务、对象信息服务,除此之外在编译器和 VCL framework 级别上提供了一些额外的服务,例如对象消息分派服务。

前言
首先说一下,Delphi 对象模型涉及的概念非常多,因此在这篇笔记中,我无法将所有的知识点都点到,只是理出一条线方便后来人。可以说这部分内容不是很容易搞懂的,建议大家多看 VCL 源码,它可真是一座金山,有你挖不完的金子,每次你都会有意外收获的。另外有些概念恐怕看源码也不见得搞得懂,这时候你可以通过 Debug 看看反汇编的结果,通常会看到编译器为你做了很多幕后工作。有了这种钻研精神,我想恐怕没有什么问题解决不了的。

正文
Delphi 中万物之源是 TObject,不管你自定义的类是否指明了所继承的父类,一定都是 TObject 的子孙,一样具有 TObject 定义的所有特性[3]。由于在 TObject 中已经提供了大部分的对象基础服务,因此继承类自然而然也就具备了这些对象服务,强烈建议每一个学 Delphi 的朋友都要仔细研习一下 TObject 的源码。
一个对象的生命周期是从它被创建那一刻开始。通常我们都用类似 TMyObject.Create 这样的语句创建对象,那么你知道在这一行代码的后面到底发生了什么事情吗?可以说,发生了无数的事情,对象也从此有了生命。

一,对象创建服务
凡是声明为 Constructor 的方法都属于构造函数,不管你用不用 Create 作为方法名称,但建议只用 Create 作为方法名称;由此可知编译器是根据 Constructor 这个指示字(directive)来生成构造代码,而不是根据 Create 这个方法名称,相当一部分人对构造函数的实现过程存在误解。
一个类实例的生成需要经过对象内存分配、内存初始化、设置对象执行框架三个步骤。
编译器首先调用 System._ClassCreate 进行对象内存分配、内存初始化的工作。而 System._ClassCreate 调用 TObject 类的虚方法 NewInstance 建立对象的实例空间,继承类通常不需要重载 TObject.NewInstance,除非你使用自己的内存管理器,因此缺省是调用 TObject.NewInstance。TObject.NewInstance 方法将根据编译器在类信息数据中初始化的对象实例尺寸(TObject.InstanceSize),调用系统缺省的 MemoryManager.GetMem 过程为该对象在堆(Heap)中分配内存,然后调用 TObject.InitInstance 方法将分配的空间初始化。InitInstance 方法首先将对象空间的头4个字节初始化为指向对象类的 VMT 的指针,然后将其余的空间清零。如果类中还设计了接口,它还要初始化接口表格(Interface Table)。
当对象实例在内存中分配且初始化后,开始设置执行框架。所谓设置执行框架就是执行你在 Create 方法里真正写的代码。设置执行框架的规矩是先设置基类的框架,然后再设置继承类的,通常用 Inherited 关键字来实现。
上述工作都做完后,编译器还要调用 System._AfterConstruction 让你有最后一次机会进行一些事务的处理工作。System._AfterConstruction 是调用虚方法 AfterConstruction 实现的。 在 TObject 中 AfterConstruction 中只是个 Place Holder,你很少需要重载这个方法,重载这个方法通常只是为了与 C Builder 对象模型兼容。
最后,编译器返回对象实例数据的地址指针。
需要注意的是,构造函数是对象和类方法的混合,可以用对象引用或者类引用来调用它[4]。类引用模式会按照上面的步骤进行对象创建,对象引用模式只会执行设置执行框架这一步,TApplication.CreateForm 是对象引用的一个实例。
相关 TObject 方法:
TObject = class
// ...
constructor Create;
class function InitInstance(Instance: Pointer): TObject;
class function InstanceSize: Longint;
procedure AfterConstruction; virtual;
class function NewInstance: TObject; virtual;
// ...
end;

function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
function _AfterConstruction(Instance: TObject): TObject;

// 别忘了看看这个创建对象的特殊范例,代码位于 Forms Unit
TApplication = class(TComponent)
public
procedure CreateForm(InstanceClass: TComponentClass; var Reference);
二,对象识别服务
对象识别服务的目的是让你可以确定目前使用的对象的类型以及继承架构[1],虽然有时候在你的代码中并没有直接使用这些类方法, 但你已经在间接调用这些方法了,比如经常使用的类操作符 is,它是调用 TObject.InheritsFrom 来实现的。
相关 TObject 方法:
TObject = class
// ...
class function ClassName: ShortString;
class function ClassNameIs(const Name: string): Boolean;
class function ClassParent: TClass;
class function InheritsFrom(AClass: TClass): Boolean;
class function InstanceSize: Longint;
// ...
end;
三,对象信息服务
TObject 中提供的对象信息服务可允许程序员深入追踪对象的构造信息,这些构造信息包括了对象的 VMT、VMT 的内容、对象支持的接口、接口之中的方法以及对象的方法地址等对象系统信息[1]。这方面的内容涉及了 RTTI、接口等诸多方面的知识,需另开文章进行阐述,请随时关注我的主页相关内容的文章发布。
特别注意:李维《Inside VCL》在解释 MethodName 方法时有误。经过验证,结论是凡是声明在类的 Published 部分的方法都可以通过调用 TObject.MethodName 获得方法的名字。 而不是只对 TComponent 继承下来的类的 Published 方法才有作用。
相关 TObject 方法:
TObject = class

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:关于Borland,Delphi9的一些杂七杂八的感想

下一篇:在delphi中建立程序的快捷方式--并将快捷方式放在开始->程序->的