DELPHI 对象的本质 VMT

时间:2022-06-19 06:25:29

TObject是所有对象的基本类,DELPHI中的任何对象都是一个指针,这个指针指明该对象在内存中所占据的一块空间!   
   对象空间的头4个字节是指向该对象类的虚方法地址表(VMT-Vritual   Method   Table)。接下来的空间就是存储对象本身成员数据的空间,并按从该对象最原始祖先类的数据成员到该对象类的数据成员的总顺序,和每一级类中数据成员的定义顺序存储。   
  类的虚方法地址表(VMT)保存从该类的原始祖先类派生到该类的所有类的虚方法的过程地址。   
  即使,我们自己并未定义任何类的虚方法,但该类的对象仍然存在指向虚方法地址表的指针,只是地址项的长度为零。可是,在TObject中定义的那些虚方法,如Destroy、FreeInstance等等,又存储在什么地方呢?原来,他们的方法地址存储在相对VMT指针负方向偏移的空间中。其实,在VMT表的负方向偏移76个字节的数据空间是对象类的系统数据结构,这些数据结构是与编译器相关的,并且在将来的DELPHI版本中有可能被改变。   
  VMT是一个从负偏移地址空间开始的数据结构,负偏移数据区是VMT的系统数据区,VMT的正偏移数据是用户数据区(自定义的虚方法地址表)。TObject中定义的有关类信息或对象运行时刻信息的函数和过程,一般都与VMT的系统数据有关,事实上,self之上就是RTTI信息。   
  一个VMT数据就代表一个类,其实VMT就是类!在Object   Pascal中我们用TObject、TComponent等等标识符表示类,它们在DELPHI的内部实现为各自的VMT数据。而用class   of保留字定义的类的类型,实际就是指向相关VMT数据的指针。   
  对我们的应用程序来说,VMT数据是静态的数据,当编译器编译完成我们的应用程序之后,这些数据信息已经确定并已初始化。我们编写的程序语句可访问VMT相关的信息,获得诸如对象的尺寸、类名或运行时刻的属性资料等等信息,或者调用虚方法或读取方法的名称与地址等等操作。当一个对象产生时,系统会为该对象分配一块内存空间,并将该对象与相关的类联系起来,于是,,在为对象分配的数据空间中的头4个字节,就成为指向类VMT数据的指针。 

//创建一个对象   obj   :=   TObject.Create;   
  1)   用   TObject   对应的   VMT   为依据,调用   TObject   的   Create   构造函数。   
  2)   而在   Create   构造函数调用了系统的   _ClassCreate   过程,   
  3)   系统的   ClassCreate   过程又通过类   VMT   调用   NewInstance   虚方法。   
  4)   调用   NewInstance   方法的目的是要建立对象的实例空间,因为我们没有重载该方法,所以,   
        它就是   TObject   类的   NewInstance。   
  5)   TObjec   类的   NewInstance   方法将根据编译器在VMT表中初始化的对象实例尺寸(InstanceSize),   
        调用   GetMem   过程为该对象分配内存,   
  6)   然后调用   InitInstance   方法将分配的空间初始化。   
  7)   InitInstance方法首先将对象空间的头4个字节初始化为指向对象类对应VMT的指针,然后将其余的空间清零。   
  8)   建立对象实例之后,还调用了一个虚方法AfterConstruction。   
  9)   最后,将对象实例数据的地址指针保存到AnObject变量中,这样,obj   对象就诞生了。   
  //消灭一个对象     Obj.Destroy;   
          TObject的析构函数Destroy被声明为虚方法,它也是系统固有的虚方法之一。   
  1)   Destory方法首先调用了   BeforeDestruction   虚方法,   
  2)   然后调用系统的   _ClassDestroy过程。   
  3)   _ClassDestory   过程又通过类VMT调用   FreeInstance   虚方法,   
  4)   由FreeInstance方法调用FreeMem过程释放对象的内存空间。