Tobject 类解析[转]

原链接:http://blog.csdn.net/zang141588761/article/details/51993900

TObject = class
    //创建
    constructor Create;
    //释放
    procedure Free;
    //初始化实列
    class function InitInstance(Instance: Pointer): TObject;
    //清除实列
    procedure CleanupInstance;
    //获得类的类型
    function ClassType: TClass;
    //获得了的名称
    class function ClassName: ShortString;
    //判断类的名称
    class function ClassNameIs(const Name: string): Boolean;
    //类的父类
    class function ClassParent: TClass;
    //类的信息指针
    class function ClassInfo: Pointer;
    //当前类的实列大小
    class function InstanceSize: Longint;
    //判断是否从一个类继承下来
    class function InheritsFrom(AClass: TClass): Boolean;
    //根据方法的名称获得方法的地址
    class function MethodAddress(const Name: ShortString): Pointer;
    //根据地址或的方法的名称
    class function MethodName(Address: Pointer): ShortString;
    //根据名称获得属性的地址
    function FieldAddress(const Name: ShortString): Pointer;
    //查询接口
    function GetInterface(const IID: TGUID; out Obj): Boolean;
    //获得接口的入口
    class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
    //获得接口表
    class function GetInterfaceTable: PInterfaceTable;
    //安全调用例外
    function SafeCallException(ExceptObject: TObject;
      ExceptAddr: Pointer): HResult; virtual;
    //创建之后的执行
    procedure AfterConstruction; virtual;
    //释放之前的执行
    procedure BeforeDestruction; virtual;
    //分派消息
    procedure Dispatch(var Message); virtual;
    //默认的句柄
    procedure DefaultHandler(var Message); virtual;
    //新的实列
    class function NewInstance: TObject; virtual;
    //释放实列
    procedure FreeInstance; virtual;
    //释放
    destructor Destroy; virtual;
end;

//初始化实列
class function TObject.InitInstance(Instance: Pointer): TObject;
{$IFDEF PUREPASCAL}
var
IntfTable: PInterfaceTable;
ClassPtr: TClass;
I: Integer;
begin
//分配需要的内存的大小
FillChar(Instance^, InstanceSize, 0);
//实列化分配好的内存
PInteger(Instance)^ := Integer(Self);
ClassPtr := Self;
//如果成功
while ClassPtr <> nil do
begin
    //获得接口表
    IntfTable := ClassPtr.GetInterfaceTable;
    //遍历接口
    if IntfTable <> nil then
      for I := 0 to IntfTable.EntryCount-1 do
//初始化每个接口函数的具体实现
with IntfTable.Entries[I] do
begin
    if VTable <> nil then
      PInteger(@PChar(Instance)[IOffset])^ := Integer(VTable);
end;
    ClassPtr := ClassPtr.ClassParent;
end;
Result := Instance;
end;

//清除实列
procedure TObject.CleanupInstance;
{$IFDEF PUREPASCAL}
var
ClassPtr: TClass;
InitTable: Pointer;
begin
//获得当前的类型
ClassPtr := ClassType;
//获得初始化标的地址 
InitTable := PPointer(Integer(ClassPtr) + vmtInitTable)^;
//如果当前类存在 并且初始化表也存在
while (ClassPtr <> nil) and (InitTable <> nil) do
begin
    //释放所有的信息
    _FinalizeRecord(Self, InitTable);
    //如果当前类有父类 则清楚父类的信息
    ClassPtr := ClassPtr.ClassParent;
    if ClassPtr <> nil then
      InitTable := PPointer(Integer(ClassPtr) + vmtInitTable)^;
end;
end;

//获得当前类的类型
function TObject.ClassType: TClass;
begin
//就是返回当前类的指针
Pointer(Result) := PPointer(Self)^;
end;

//获得当前类的类名
class function TObject.ClassName: ShortString;
{$IFDEF PUREPASCAL}
begin
//根据虚拟方发表返回指定的地址
Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
end;

// 判断当前类的类名
class function TObject.ClassNameIs(const Name: string): Boolean;
{$IFDEF PUREPASCAL}
var
Temp: ShortString;
I: Byte;
begin
Result := False;
//获得当前类的类名得指针
Temp := ClassName;
//根据字符串的长度比较每个字符 区分大小写
for I := 0 to Byte(Temp[0]) do
    if Temp[I] <> Name[I] then Exit;
Result := True;
end;

//获得当前类的父类
class function TObject.ClassParent: TClass;
{$IFDEF PUREPASCAL}
begin
//根据虚拟方法表或的父的地址指针
Pointer(Result) := PPointer(Integer(Self) + vmtParent)^;
//如果存在父类 则返回
if Result <> nil then
    Pointer(Result) := PPointer(Result)^;
end;
{$ELSE}
asm
        MOV     EAX,[EAX].vmtParent
        TEST    EAX,EAX
        JE      @@exit
        MOV     EAX,[EAX]
@@exit:
end;

//获得类型信息
class function TObject.ClassInfo: Pointer;
begin
Result := PPointer(Integer(Self) + vmtTypeInfo)^;
end;

//获得实列大小
class function TObject.InstanceSize: Longint;
begin
Result := PInteger(Integer(Self) + vmtInstanceSize)^;
end;

//判断是否从一个类继承下来
class function TObject.InheritsFrom(AClass: TClass): Boolean;
{$IFDEF PUREPASCAL}
var
ClassPtr: TClass;
begin
ClassPtr := Self;
//当前类是否存在 并且和比较的类不等 
while (ClassPtr <> nil) and (ClassPtr <> AClass) do
     //获得这个类的父类
    ClassPtr := PPointer(Integer(ClassPtr) + vmtParent)^;
Result := ClassPtr = AClass;
end;
{$ELSE}
asm
        { ->    EAX     Pointer to our class    }
        {       EDX     Pointer to AClass               }
        { <-    AL      Boolean result          }
        JMP     @@haveVMT
@@loop:
        MOV     EAX,[EAX]
@@haveVMT:
        CMP     EAX,EDX
        JE      @@success
        MOV     EAX,[EAX].vmtParent
        TEST    EAX,EAX
        JNE     @@loop
        JMP     @@exit
@@success:
        MOV     AL,1
@@exit:
end;

//根据方法名称获得地址
class function TObject.MethodAddress(const Name: ShortString): Pointer;
asm
        { ->    EAX     Pointer to class        }
        {       EDX     Pointer to name }
        PUSH    EBX
        PUSH    ESI
        PUSH    EDI
        XOR     ECX,ECX           //清零
        XOR     EDI,EDI           //清零
        MOV     BL,[EDX]          //获得字符串的长度
        JMP     @@haveVMT         //判断是否有虚拟方发表
@@outer:                                { upper 16 bits of ECX are 0 ! }
        MOV     EAX,[EAX]
@@haveVMT:
        MOV     ESI,[EAX].vmtMethodTable //获得虚拟方发表的地址
        TEST    ESI,ESI                   //是否存在
        JE      @@parent                  //如果不存在
        MOV     DI,[ESI]                { EDI := method count           }方法的数量
        ADD     ESI,2                     // 开始 
@@inner:                                { upper 16 bits of ECX are 0 ! }
        MOV     CL,[ESI+6]              { compare length of strings     } //获得名城的长度
        CMP     CL,BL                                                      //比较长度 
        JE      @@cmpChar                                                  //如果相等就开始比较字符
@@cont:                                 { upper 16 bits of ECX are 0 ! }
        MOV     CX,[ESI]                { fetch length of method desc   } //获得方法的长度 //长度两个字节 指针4个字节 ///
        ADD     ESI,ECX                 { point ESI to next method      } //指向下一个函数
        DEC     EDI
        JNZ     @@inner
@@parent:                              //获得父的方发表
        MOV     EAX,[EAX].vmtParent     { fetch parent vmt              }
        TEST    EAX,EAX                //是否为0 
        JNE     @@outer                //不为零
        JMP     @@exit                  { return NIL                    } //已经到根

@@notEqual:
        MOV     BL,[EDX]                { restore BL to length of name } //存储名字的长度
        JMP     @@cont                                                    //转移

@@cmpChar:                              { upper 16 bits of ECX are 0 ! }
        MOV     CH,0                    { upper 24 bits of ECX are 0 ! } ///清空高位字节
@@cmpCharLoop:
        MOV     BL,[ESI+ECX+6]          { case insensitive string cmp   } //获得第一个字符
        XOR     BL,[EDX+ECX+0]          { last char is compared first   } //比较
        AND     BL,$DF                                                     //清空其他标志位 
        JNE     @@notEqual
        DEC     ECX                      { ECX serves as counter         } //比较下一个
        JNZ     @@cmpCharLoop                                              //如果不为零 进行下一个字符的比较

{ found it }
        MOV     EAX,[ESI+2]              //找到 并且得到指针 12 方法长度 3456 方法指针 7890 方法名称 7 方法名城的长度

@@exit:
        POP     EDI
        POP     ESI
        POP     EBX
end;

//根据字段名获得地址
function TObject.FieldAddress(const Name: ShortString): Pointer;
asm
{ ->    EAX     Pointer to instance     }
        {       EDX     Pointer to name }
        PUSH    EBX
        PUSH    ESI
        PUSH    EDI
        XOR     ECX,ECX                 //清空Cx 
        XOR     EDI,EDI                 //清空Edit                     
        MOV     BL,[EDX]                //获得Name的长度

PUSH    EAX                     { save instance pointer         } //保存当前实列指针

@@outer:
        MOV     EAX,[EAX]               { fetch class pointer           } //获得当前类的指针
        MOV     ESI,[EAX].vmtFieldTable                                   //获得字段列表的地址
        TEST    ESI,ESI                                                   //是否存在
        JE      @@parent                                                  //如果不存在就到当前的父类查找
        MOV     DI,[ESI]                { fetch count of fields         } //获得字段的数量
        ADD     ESI,6                                                     // 2 为数量 4 位指针 
@@inner:
        MOV     CL,[ESI+6]              { compare string lengths        } //获得当前字段的长度
        CMP     CL,BL                                                     //比较长度
        JE      @@cmpChar                                                 //如果相等 就开始比较 字符
@@cont: ///LEA是取变量的地址 
        LEA     ESI,[ESI+ECX+7] { point ESI to next field       }         //Esi指向下一个字段ESI 当前位子+ECX 长度+7 ???
        DEC     EDI                                                       //数量减一
        JNZ     @@inner                                                   //如果不等于零则继续比较
@@parent: 
        MOV     EAX,[EAX].vmtParent     { fetch parent VMT              } //获得当前的父类地址
        TEST    EAX,EAX                                                   //是否存在   
        JNE     @@outer                                                   //如果存在则准备获得字段数量 
        POP     EDX                     { forget instance, return Nil   } //否则恢复Edx 恢复实列 返回nil 当前Eax为空
        JMP     @@exit                                                    //并且退出

@@notEqual:
        MOV     BL,[EDX]                { restore BL to length of name } //获得目的字段名称的长度
        MOV     CL,[ESI+6]              { ECX := length of field name   } //获得源字段名城的长度
        JMP     @@cont

@@cmpChar:
        MOV     BL,[ESI+ECX+6] { case insensitive string cmp   }          //字符比较
        XOR     BL,[EDX+ECX+0] { starting with last char       }
        AND     BL,$DF                                                     //标志位处理
        JNE     @@notEqual                                                 //如果不等
        DEC     ECX                     { ECX serves as counter         } //字符长度减一
        JNZ     @@cmpChar                                                  //如果还有没有比较完的字符

{ found it }
        MOV     EAX,[ESI]           { result is field offset plus ...   } //获得当前的地址的偏移量
        POP     EDX                                                        //恢复当前实列到Edx
        ADD     EAX,EDX         { instance pointer              }          //获得字段的偏移地址

@@exit:
        POP     EDI
        POP     ESI
        POP     EBX
end;

//

function TObject.GetInterface(const IID: TGUID; out Obj): Boolean;
var
InterfaceEntry: PInterfaceEntry;
begin
Pointer(Obj) := nil;
InterfaceEntry := GetInterfaceEntry(IID);
if InterfaceEntry <> nil then
begin
    if InterfaceEntry^.IOffset <> 0 then
    begin
      Pointer(Obj) := Pointer(Integer(Self) + InterfaceEntry^.IOffset);
      if Pointer(Obj) <> nil then IInterface(Obj)._AddRef;
    end
    else
      IInterface(Obj) := InvokeImplGetter(Self, InterfaceEntry^.ImplGetter);
end;
Result := Pointer(Obj) <> nil;
end;

----------------------
一个实列的创建过程
s:=Tstrings.create ;
Mov Dl ,$01,
Mov Eax , [$00412564]; //??
Call Tobject.create ;
    {
     Test dl,dl ;
     Jz +$08    ///???
     Add Esp,-$10;
     Call @ClassCreate;
     { 
       push   Edx,
       Push   Ecx,
       Push   Ebx,
       Test Dl,dl 
       jl   +03
       Call Dword Ptr[eax-$0c]
         { 
           NewInStance
           push Ebx
           mov Ebx ,eax
           mov Eax ,ebx
           Call Tobject.instancesize
             {
              Add Eax,-$28
              Mov Eax,[Eax]
              Ret                           
              }
           Call @GetMem
             {
              push Ebx
              Test Eax,Eax
              jle +$15
              Call Dword ptr [memoryManager]
              Mov Ebx,Eax
              Test Ebx,ebx
              Jnz +$0B
              mov Al,%01
              Call Error
              Xor Ebx,Ebx
              pop Ebx
              Ret
              }
           mov Edx,Eax
           Mov Eax,Ebx,
           call Tobject.initInstance
           pop Ebx            
          
           }
       Xor Edx,edx
       Lea Ecx,[Esp+$10]
       Mov Ebx,Fs:[Edx]
       mov [Ecx],EDx
       mov [Ecx+$08],ebx
       mov [Ecx+$04],$0040340D
       mov Fs:[Edx] , Ecx
       pop Ebx
       pop Ecx
       pop Edx
      }
         
        } 
     Test dl,dl,
     jz +0f 
     Call @AfterConStruction
     pop Dword ptr Fs:[$00000000]
     Add Esp ,$0c    
    }

一个类实例的生成需要经过对象内存分配、内存初始化、设置对象执行框架三个步骤。
    编译器首先调用 System._ClassCreate 进行对象内存分配、内存初始化的工作。而 System._ClassCreate 调用 TObject 类的虚方法 NewInstance 建立对象的实例空间,继承类通常不需要重载 TObject.NewInstance,除非你使用自己的内存管理器,因此缺省是调用 TObject.NewInstance。TObject.NewInstance 方法将根据编译器在类信息数据中初始化的对象实例尺寸(TObject.InstanceSize),调用系统缺省的 MemoryManager.GetMem 过程为该对象在堆(Heap)中分配内存,然后调用 TObject.InitInstance 方法将分配的空间初始化。InitInstance 方法首先将对象空间的头4个字节初始化为指向对象类的 VMT 的指针,然后将其余的空间清零。如果类中还设计了接口,它还要初始化接口表格(Interface Table)。
    当对象实例在内存中分配且初始化后,开始设置执行框架。所谓设置执行框架就是执行你在 Create 方法里真正写的代码。设置执行框架的规矩是先设置基类的框架,然后再设置继承类的,通常用 Inherited 关键字来实现。
    上述工作都做完后,编译器还要调用 System._AfterConstruction 让你有最后一次机会进行一些事务的处理工作。System._AfterConstruction 是调用虚方法 AfterConstruction 实现的。 在 TObject 中 AfterConstruction 中只是个 Place Holder,你很少需要重载这个方法,重载这个方法通常只是为了与 C++ Builder 对象模型兼容。
    最后,编译器返回对象实例数据的地址指针。

对象释放服务其实就是对象创建服务的逆过程,可以认为对象释放服务就是回收对象在创建过程中分配的资源。
    当编译器遇到 destructor 关键字通常会这样编码:首先调用 System._BeforeDestruction,而 System._BeforeDestruction 继而调用虚方法 BeforeDestruction, 在 TObject 中 BeforeDestruction 中只是个 Place Holder,你很少需要重载这个方法,重载这个方法通常只是为了与 C++ Builder 对象模型兼容。
    这之后,编译器调用你在 Destroy 中真正写的代码,如果当前你在撰写的类是继承链上的一员,不要忘记通过 inherited 调用父类的析构函数以释放父类分配的资源,但规矩是,先释放当前类的资源,然后再调用父类的,这和对象创建服务中设置对象执行框架的顺序恰好相反。
    当前类及继承链中所有类中分配的资源全部释放后,最后执行的就是释放掉对象本身及一些特别数据类型占用的内存空间。编译器调用 System._ClassDestroy 来完成这件工作。System._ClassDestroy 继而调用虚方法 FreeInstance,继承类通常不需要重载 TObject.FreeInstance,除非你使用自己的内存管理器,因此缺省是调用 TObject.FreeInstance。TObject.FreeInstance 继而调用 TObject.CleanupInstance 完成对于字符串数组、宽字符串数组、Variant、未定义类型数组、记录、接口和动态数组这些特别数据类型占用资源的释放[4],最后 TObject.FreeInstance 调用 MemoryManager.FreeMem 释放对象本身占用的内存空间。 
    很有意思的是,对象释放服务与对象创建服务所用方法、函数是一一对应的,是不是有一种很整齐的感觉?
对象创建服务
对象释放服务
System._ClassCreate
System._ClassDestroy
System._AfterConstruction
System._BeforeDestruction
TObject.AfterConstruction(virtual)
TObject.BeforeDestruction(virtual)
TObject.NewInstance(virtual)
TObject.FreeInstance(virtual)
TObject.InitInstance
TObject.CleanupInstance
MemoryManager.GetMem
MemoryManager.FreeMem
     还有一点要注意,通常我们不会直接调用 Destroy 来释放对象,而是调用 TObject.Free,它会在释放对象之前检查对象引用是否为 nil。

时间: 2024-10-09 14:37:36

Tobject 类解析[转]的相关文章

Tobject 类解析

TObject = class    //创建    constructor Create;    //释放    procedure Free;    //初始化实列    class function InitInstance(Instance: Pointer): TObject;    //清除实列    procedure CleanupInstance;    //获得类的类型    function ClassType: TClass;    //获得了的名称    class f

Thrift compiler代码生成类解析

代码生成类解析: Thrift--facebook RPC框架,介绍就不说了,百度,google一大把,使用也不介绍,直接上结构和分析吧. Hello.thrift文件内容如下: namespace java com.tomsun.thrift.generated.demo service Hello { string helloString(1:string para) } 内容很简单,申明个RPC service(Hello),服务方法helloString,方法参数格式(seq: para

Delphi中的Sender:TObject对象解析

Delphi中的Sender:TObject对象解析 procedure TForm1.Button1Click(Sender: TObject); begin end; 解析:Procedure是过程,TForm是窗体类,加上数字就是某个窗体,像TForm1就是Form1窗体. Button1是你的按钮控件的名称,Button1Click就是按钮的单击事件,(Sender:Tobject)就是发送消息到对象,这里默认为本窗体. Sender的类型是Tobject,是Tobject的派生类. D

C++ 模板类解析

具体模板类作用这边就不细说了,下面主要是描述下模板类的使用方法以及注意的一些东西. #include <iostream> using namespace std; template <typename numtype> //定义类模板 class Compare { public : Compare(numtype a,numtype b) {x=a;y=b;} numtype max( ) {return (x>y)?x:y;} numtype min( ) {retur

Bootstrap 类解析

Bootstrap 类解析 元素 Bootstrap 类 定义 <div> container 内容容器 <table> table 表格 <table> table-striped 带条纹背景的表格 <button> btn 按钮 <button> btn-success 成功按钮 <span> glyphicon 字形图标 <span> glyphicon-pencil 铅笔图标 <span> glyphi

FilterEngine 类解析——OpenCV图像滤波核心引擎(zz)

<2>FilterEngine 类解析——OpenCV图像滤波核心引擎 FilterEngine类是OpenCV关于图像滤波的主力军类,OpenCV图像滤波功能的核心引擎.各种滤波函数比如blur, GaussianBlur,到头来其实是就是在函数末尾处定义了一个Ptr<FilterEngine>类型的f,然后f->apply( src, dst )了一下而已. 这个类可以把几乎是所有的滤波操作施加到图像上.它包含了所有必要的中间缓存器.有很多和滤波相关的create系函数的

[C# | XML] XML 反序列化解析错误:&lt;xml xmlns=&#39;&#39;&gt; was not expected. 附通用XML到类解析方法

使用 XML 反化时出现错误: public static TResult GetObjectFromXml<TResult>(string xmlString) { TResult result; XmlSerializer serializer = new XmlSerializer(typeof(TResult), new XmlRootAttribute("xml")); using (TextReader tr = new StringReader(xmlStri

Spark 资源调度包 stage 类解析

spark 资源调度包 Stage(阶段) 类解析 类注释: /** * A stage is a set of parallel tasks all computing the same function that need to run as part * of a Spark job, where all the tasks have the same shuffle dependencies. * 一个阶段是所有计算相同功能的并行任务集合, 作为spark作业的一部分, 这些任务都有相同

不适用工具类解析Json

解析的数据: { "citycode": "101051301", "citydesc": "黑龙江 双鸭山", "cityname": "双鸭山", "data": [ { "date": "2015-08-29", "icon": "d07|n07", "temperatur