Delphi中虚拟方法表和动态方法表 转载 https://www.cnblogs.com/hxy00/archive/2011/07/19/2110209.html
方法来到类中, 以前的特点基本都在;
因为类一般是存在于一个继承链中, 所以就有了一些新的概念, 譬如: 继承、覆盖;
也有了很多新名称, 譬如: 静态方法、虚方法、动态方法、抽象方法、类方法、消息方法.
先从虚方法与动态方法开始吧
//下面的类中就定义了两个虚方法(virtual)、两个动态方法(dynamic)
TMyClass = class
procedure Proc1(x,y: Real); virtual;
function Fun1(x,y: Real): Real; virtual;
procedure Proc2(x,y: Real); dynamic;
function Fun2(x,y: Real): Real; dynamic;
end;
//定义成虚方法或动态方法, 就意味着在后来的子类中将要被覆盖(override), 也就是重写
TBass = class
procedure Proc(x,y: Real); virtual;
function Fun(x,y: Real): Real; dynamic;
end;
TChild = class(TBass)
procedure Proc(x,y: Real); override;
function Fun(x,y: Real): Real; override;
end;
{正是因为这种机制而形成了多态}
//那虚方法和动态方法有什么区别呢?
13.8px">
每个类都内含着两个表: 虚方法表(VMT)和动态方法表(DMT);
VMT 表包含着本类与其所有父类的虚方法 - 那一般会是一个比较庞大的表;
DMT 表只包含本类的动态方法 - 如果要调用其上层类的动态方法, 只能逐级查找;
因此, 使用虚方法速度上会有优势, 使用动态方法会节约内存;
在 Delphi 初期只有 virtual 而没有 dynamic ; 后来随着 VCL 日渐庞大, 才有了 dynamic ;
譬如类的事件方法一般都是在早期定义, 为了节约空间, 事件方法在 VCL 中基本都定义成了 dynamic ;
这样看来: virtual 和 dynamic 并没有太多区别, 一个侧重速度、一个节约空间; 它们是可以互相代替的!
另外: 因为它们区别不大, 并且是先有 virtual , 所以人们也习惯于把"虚方法"和"动态方法"都称作"虚方法".
Delphi中所有类都直接或者间接派生于TObject,一个TObject的实例:Object(对象)实际上是一个4字节的指针。该指针指向对象的实际数据区(Object
Data)。对象的数据区划分很多的小区域,这些区域分为两部分:
(1)前4个字节存放一个指针,该指针指向另一个地址区域。
(2)其余小区域分别存放对象的各种数据成员。
前四个字节字节的指针指向另一地址区域即“虚拟方法表(virtual method table,VMT)”,虚拟方法表又划分很多个大小为4字节的小区域,每个区域存放一个指针,每个指针对应一个虚拟方法的入口地址;其余小区域存放字段、
属性值和所有的非虚方法的入口地址。由此可见废墟方法的存取相对简单,而虚方法的寻址与调用要复杂的多。
1、 虚拟方法表结构
如下图所示,一个对象指针指向一个对象数据域,对象数据域的前四个字节存放一个指针,该指针指向虚拟方法表。
2、VMT的产生
参照虚拟方法结构图,VMT表的负偏移区(-76~0)是基础信息,存储基础性数据(如实例大小、
接口表、运行时类型信息表、字段表、方法表、类名和父类虚拟方法表等)的指针和多有的基础性虚拟
方法的指针,而不全是指针列表,这个区域主要来帮助实现对象的构造与析构、运行是类型信息存取、
字段和方法解析等,大小固定;正偏移区是用户定义的虚拟方法所在区域,每四个字节一个用户定义
的虚拟方法指针。这些虚拟方法不仅指在本类定义的,还包括从Tobject一直到本类的所有中间类定义的虚拟方法。
3、虚拟方法与动态方法比较
实际应用中虚方法常见两类:虚拟方法(Virtual)和动态方法(Dyniamic),由上知Virtual方法被全部列入VMT的正偏移区,
当一个对象请求调用Virtual方法时,可以在类的VMT中直接寻址,然后调用,除非调用一个Dynamic方法;
一个动态方法表(DMT)来存储动态方法的入口地址,这是虚拟方法和动态方法调用的一个重大区别,而DMT又依赖于VMT来实现。
DMT是一系列的指针列表,和VMT正偏移类似,存放了本类定义的和从父类继承并覆盖后的动态方法的入口地址。
虚拟方法和动态方法相比,使用动态方法可以节省内存,因为它不存放未曾覆盖的虚方法指针,
而且调用一个虚方法和调用在DMT中存放了入口地址的动态方法相比,速度没有显著差异。而如果使用虚拟方法,
即使子类没有覆盖父类虚拟方法,子类中和父类也都会存放虚拟方法的入口地址。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律