Delphi高手突破第二章(4),VMT与DMT
2012-08-09 04:28
246 查看
==============================VMT===================================
在创建一个类的实例之后,编译器在该对象的内存空间的首4个字节安插一个指针,该指针指向的地址称为VMT(Virtual Method Table,虚方法表),这个表中放了该类的所有虚方法的入口地址。
在Object Pascal中,所有类实例都会有这么一个指向VMT的指针。如果没有在类中声明虚方法,则该指针为nil。
没有被派生类赋给的方法,编译器会将基类的该方法实现的入口地址填入派生类的VMT中。
其实“指向VMT的指针”所指向的VMT,其实只是真正VMT的一部分,也就是用户定义的第一个虚方法的位置。如果以这个位置为原点,向正方向即刚才所说的VMT,而向负方向,则是语言定义的另一些信息所在地址,析构函数地址就被放在了负方向上了。所以VMT中也有析构函数,但没有出现在我们所能见到的VMT中。这样做的目的,是为了与C++以及COM的VMT相兼容。
据观察:负方向包括7个TObject的虚函数(包括析构函数,位置-4),以及指向其它表格的指针(虚方法表, 接口表, Automation information table, 实例初始化表, 类型信息表,属性表, 方法表, DMT(动态方法表), 类名, 实例大小,指向祖先类指针,安全异常指针)
==============================DMT====================================
VMT的-48处是一个指向DMT的指针,它与VMT有什么关系?
派生类的虚方法表完全继承了基类的虚方法表,只是将被覆盖的虚方法地址变了。基类和每个派生类都有一份自己的虚方法表。可以想象,随着类层次的扩展,虚方法将耗费非常大的内存空间。为了防止这种情况,Object Pascal引入了“dynamic”的概念。dynamic和virtual方法实现相同的功能,只有声明的关键字不同。被声明为dynamic的方法,其入口地址将被放在DMT中。
VMT和DMT的区别在于:对于派生类没有覆盖的方法,这些方法的入口地址不会出现在DMT中,编译器要通过基类的信息来寻找它们的入口地址。
DMT中不会出现没有被派生类覆盖的基类dynamic方法,因此DMT会比VMT节省空间,但是DMT中对基类的动态方法的寻址不是直接进行的,因此dynamic要比virtual要慢一些。当基类有许多虚方法,而派生类只覆盖很少几个时,区别尤其明显。当派生层次越来越深,派生数量越来越多时,DMT就能节省更多的内存空间。virtual与dynamic的区别仅在于编译器采用不同的晚绑定策略而已,对于程序员而言,它们的功能相同。
几乎每个派生类都要覆盖的方法,将它声明为virtual;
如果层次很深,或者派生类很多,但某个方法只被很少的派生类赋给,则声明为dynamic。
另外需要注意的是,只有VMT才与C++、COM的vtable兼容。如果需要这样的兼容性时,只能使用virtual。
在创建一个类的实例之后,编译器在该对象的内存空间的首4个字节安插一个指针,该指针指向的地址称为VMT(Virtual Method Table,虚方法表),这个表中放了该类的所有虚方法的入口地址。
在Object Pascal中,所有类实例都会有这么一个指向VMT的指针。如果没有在类中声明虚方法,则该指针为nil。
没有被派生类赋给的方法,编译器会将基类的该方法实现的入口地址填入派生类的VMT中。
其实“指向VMT的指针”所指向的VMT,其实只是真正VMT的一部分,也就是用户定义的第一个虚方法的位置。如果以这个位置为原点,向正方向即刚才所说的VMT,而向负方向,则是语言定义的另一些信息所在地址,析构函数地址就被放在了负方向上了。所以VMT中也有析构函数,但没有出现在我们所能见到的VMT中。这样做的目的,是为了与C++以及COM的VMT相兼容。
据观察:负方向包括7个TObject的虚函数(包括析构函数,位置-4),以及指向其它表格的指针(虚方法表, 接口表, Automation information table, 实例初始化表, 类型信息表,属性表, 方法表, DMT(动态方法表), 类名, 实例大小,指向祖先类指针,安全异常指针)
==============================DMT====================================
VMT的-48处是一个指向DMT的指针,它与VMT有什么关系?
派生类的虚方法表完全继承了基类的虚方法表,只是将被覆盖的虚方法地址变了。基类和每个派生类都有一份自己的虚方法表。可以想象,随着类层次的扩展,虚方法将耗费非常大的内存空间。为了防止这种情况,Object Pascal引入了“dynamic”的概念。dynamic和virtual方法实现相同的功能,只有声明的关键字不同。被声明为dynamic的方法,其入口地址将被放在DMT中。
VMT和DMT的区别在于:对于派生类没有覆盖的方法,这些方法的入口地址不会出现在DMT中,编译器要通过基类的信息来寻找它们的入口地址。
DMT中不会出现没有被派生类覆盖的基类dynamic方法,因此DMT会比VMT节省空间,但是DMT中对基类的动态方法的寻址不是直接进行的,因此dynamic要比virtual要慢一些。当基类有许多虚方法,而派生类只覆盖很少几个时,区别尤其明显。当派生层次越来越深,派生数量越来越多时,DMT就能节省更多的内存空间。virtual与dynamic的区别仅在于编译器采用不同的晚绑定策略而已,对于程序员而言,它们的功能相同。
几乎每个派生类都要覆盖的方法,将它声明为virtual;
如果层次很深,或者派生类很多,但某个方法只被很少的派生类赋给,则声明为dynamic。
另外需要注意的是,只有VMT才与C++、COM的vtable兼容。如果需要这样的兼容性时,只能使用virtual。
相关文章推荐
- Delphi高手突破第二章(2),对象大小,类方法与类引用,错误的面向对象设计
- Delphi高手突破第二章(3),封装,继承,多态
- Delphi高手突破第二章(1),堆与栈,构造与析构函数
- Delphi高手突破学习笔记一
- 【读书笔记】【delphi高手突破】TCanvas与Windows GDI
- delphi高手突破学习笔记之面向对象类和对象的本质
- 【读书笔记】【Delphi高手突破】TCanvas
- 【读书笔记】【Delphi高手突破】TGraphicControl/TcustomControl 与画布(Canvas)
- Delphi高手突破学习笔记三
- delphi VCL研究之消息分发机制-delphi高手突破读书笔记
- delphi高手突破学习笔记之面向对象类和对象的本质
- delphi高手突破之异常及错误处理
- 鼓励,很多的,Delphi高手突破,外加冷水一瓢
- delphi高手突破学习笔记之面向对象类和对象的本质(有汇编解释 good)
- 【读书笔记】【Delphi高手突破】TControl与Windows消息的封装
- delphi高手突破之异常及错误处理
- [转]李战大师-悟透delphi-第二章 DELPHI与WIN32时空
- 向Delphi高手进阶的几本书籍
- 万一的delphi博客写得太好了,真是有专门研究delphi的高手
- Delphi 快捷键 让你更像高手!! (form DFW)