- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
探索 Delphi类与对象的内存结构
初次接触 DELPHI 对它提供的 RAD 快速编程模式颇感神奇,随手拖放及格控件设定些属性一个应用程序就诞生了,我正是被这种特性所吸引。随着深入,慢慢的窥探到了 DELPHI 的 VCL 体系,知道了随手拖放背后隐藏的秘密:一切都起源于 VCL 的对象体系,一切都是面对对象的编程思想。Object pascal 就是是怎样实现这个体系的呢,它究竟是如何将面对对象的特性表现出来的呢,Delphi 的类和对象究竟是以什么样的形式存在的呢。带着这些问题我翻阅了一些书籍,也借鉴了一些网友的成果,做了下面的探索。
动态内存与静态内存
程序需要执行必须先装载入内存,任何程序表现的数据都存在内存中。当程序运行时,系统首先将所有数据装载入内存,完成初始化,然后从入口地址开始执行代码。程序装载后即存在于内存空间中的数据我们称之为静态内存,运行过程中分配的内存我们称之为动态内存。Delphi 的类是由编译期间决定的,编译完成后即固定在程序中,所以类是存在于静态内存中。对象是由运行期间创建的,所以对象属于动态内存。
注意:后面所提到的 TObject 均为泛指所有类,而非真正的 TObject 类
程序运行示意图
类的内存结构
类的内存结构是固定的,编译完成后就无法改变。它主要存储了类的基本信息,派生对象内存大小,虚方法列表,动态方法列表,公开属性和方法列表(published),接口列表,TObject 类的一些方法等等有关于构建对象所必须的信息。这些信息的存储位置在 SYSTEM 单元中有定义:
vmtSelfPtr
= -76;
指向虚方法表的指针
vmtIntfTable
= -72;
指向接口表的指针
vmtAutoTable
= -68;
指向自动化信息表的指针
vmtInitTable
= -64;
指向实例初始化表的指针
vmtTypeInfo
= -60;
指向类型信息表的指针,这里的数据对于RTTI 来说非常重
要,它指向一个 PTypeInfo 类型的指针,有兴趣可以看看 TypInfo 单元
vmtFieldTable = -56; 指向域定义表的指针(我开始认为是 Published Field,但实际查询时却为 NIL)
vmtMethodTable
=
-52;
指向方法定义表的指针(Published)
vmtDynamicTable
=
-48;
指向动态方法表的指针
vmtClassName
=
-44;
指向类名字符串的指针
vmtInstanceSize = -40; 对象实例的大小
vmtParent = -36; 指向父类的指针
vmtSafeCallException = -32 deprecated; 以下都是 TOBJECT 类的一些虚拟方法指针
vmtAfterConstruction = -28 deprecated; vmtBeforeDestruction = -24 deprecated; vmtDispatch = -20 deprecated; vmtDefaultHandler = -16 deprecated; vmtNewInstance = -12 deprecated; vmtFreeInstance = -8 deprecated; vmtDestroy = -4 deprecated;
如果获取对象大小,可以使用以下代码:
Result := PInteger(Integer(TObject) + vmtInstanceSize)^;
其他各项可以依此类推。
静态方法
类的静态方法在编译期间就决定了它的地址,类只为所有的派生的对象提供统一的一份静态方法表, 不会为每个对象复制一份,所以不必关心静态方法的存储(实际上静态方法也是和动态方法有序的排列在一块的,顺序与方法的实现顺序有关)
非静态方法
虚方法(Virtual)和动态方法(Dynamic)均为非静态方法,它们是用来实现面对对象的多态性的关键 特性。通过这种特性,开发者可以根据需要在不同的子类中拥有不同的实现,从而使设计变得更加灵活。在具体实现中,编译器只需要将简单的改变表中方法指针的指向即可达到目的。从语法上讲虚拟方法和动态方法是没有任何区别的,凡是声明了该两种类型的方法,在子类中都可以通过 override 关键字进行覆盖。但实际上二者的实现是存在巨大差别的:
vmtSelfPtr(虚方法表的指针)实际上就是指向 TObject 位置,所以类的虚拟方法是依次排在 TObje ct 所指向的位置之后。
vmtDynamicTable(动态方法表的指针)指向的是动态方法表,动态方法表的结构与虚方法表的结构有所不同。
两者实现方式的不同体现了两者作用的
原创力文档


文档评论(0)