Delphi的对象模型

品雪 2001.2.18
pinxue@hotmail.com http://pinxue.yeah.net

玩Delphi已经有很久了,从1.0玩到5.0。前些时候才忽然发现,居然连objectpascal的对象模型都没概念,于是花了些功夫摸了摸。现在整理成文,以飨同好。

objectpascal里有两种类,一种是由class关键字定义的,另一种是由object关键字定义的,object这种已经很少有人用了,也不能利用VCL,只是为了与borland pascal 5.5/6.0而保留着。所以俺只看了看class的。

在运行时,Delphi中定义的类是以这种形式存在的:

图上的IntfName应该是IntfTable,当时画错了,暂也懒得改它。

简单解释一下,按照borland开发组的观点,类的起点在0x048964,也就是从VirtualMethodTable开始的,所以在system.pas中称这个结构为vmt。其实它并不是一个virtual method table那么简单,从0x048964开始的-76个字节(这个数字供仅理解原理之用,未来可能变动,如果在程序中使用它后果自负),是delphi对象模型的核心。

对于类实例来说,其头四个节字是指向所属类vmt的指针(vptr),所占内存字节数由vmt的InstanceSize决定(至少为4,显然是保存vptr的需要)。

当类创建时,会调用NewInstance方法分配实例内存,并通过Parent找到父类的实例化预处理工作。

在delphi中有两种“虚方法”:virtual和dynamic。DynamicTable指向一块内存,由dynamic table counter和dynamic method函数指针组成,而虚方法则直接放在vmt的尾部,显然,在vmt的SelfPtr所指的0x408964处开始的才是真正意义上的虚方法表,这也是borland管这个字段叫SelfPtr的原因吧。DynamicTable所指的内存就在vmt不远处,但这并不是必要的。

RTTI则是由ClassName、TypeInfo、FieldTable、MethodTable组成的,注意只有publish的field和method才会进入FieldTable和MethodTable,所以,显然的只有publish的成员才存在RTTI信息。

最有意思属IntfTable和AutoTable,这是为了支持COM技术而存在的,IntfTable所指的是一个标准的COM接口表,AutoTable则用于支持自动化(时间及兴趣关系,自动化我没有测试)。IntfTable表格式已经搞清楚,但等我哪天有空再整理出来吧,其实在delphi5编程指南一书的第23章已经说得很清楚了。这也就是说delphi里的对象和com有不可分割的联系,当你使用interface关键字时,你就是在定义COM接口。

//上面用到的程序、研究过程还有一些其它资料等我有空再补上。