日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

TObject简要说明-对象的创建流程

發(fā)布時(shí)間:2025/3/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TObject简要说明-对象的创建流程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Delphi:TObject簡(jiǎn)要說明-對(duì)象的創(chuàng)建流程2009-08-14 08:57TObject = class //創(chuàng)建 constructor Create; //釋放 procedure Free; //初始化實(shí)列 class function InitInstance(Instance: Pointer): TObject; //清除實(shí)列 procedure CleanupInstance; //獲得類的類型 function ClassType: TClass; //獲得了的名稱 class function ClassName: ShortString; //判斷類的名稱 class function ClassNameIs(const Name: string): Boolean; //類的父類 class function ClassParent: TClass; //類的信息指針 class function ClassInfo: Pointer; //當(dāng)前類的實(shí)列大小 class function InstanceSize: Longint; //判斷是否從一個(gè)類繼承下來 class function InheritsFrom(AClass: TClass): Boolean; //根據(jù)方法的名稱獲得方法的地址 class function MethodAddress(const Name: ShortString): Pointer; //根據(jù)地址或的方法的名稱 class function MethodName(Address: Pointer): ShortString; //根據(jù)名稱獲得屬性的地址 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; //安全調(diào)用例外 function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; virtual; //創(chuàng)建之后的執(zhí)行 procedure AfterConstruction; virtual; //釋放之前的執(zhí)行 procedure BeforeDestruction; virtual; //分派消息 procedure Dispatch(var Message); virtual; //默認(rèn)的句柄 procedure DefaultHandler(var Message); virtual; //新的實(shí)列 class function NewInstance: TObject; virtual; //釋放實(shí)列 procedure FreeInstance; virtual; //釋放 destructor Destroy; virtual; end; //初始化實(shí)列 class function TObject.InitInstance(Instance: Pointer): TObject; {$IFDEF PUREPASCAL} var IntfTable: PInterfaceTable; ClassPtr: TClass; I: Integer; begin //分配需要的內(nèi)存的大小 FillChar(Instance^, InstanceSize, 0); //實(shí)列化分配好的內(nèi)存 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 //初始化每個(gè)接口函數(shù)的具體實(shí)現(xiàn) with IntfTable.Entries[I] do begin if VTable <> nil then PInteger(@PChar(Instance)[IOffset])^ := Integer(VTable); end; ClassPtr := ClassPtr.ClassParent; end; Result := Instance; end; //清除實(shí)列 procedure TObject.CleanupInstance; {$IFDEF PUREPASCAL} var ClassPtr: TClass; InitTable: Pointer; begin //獲得當(dāng)前的類型 ClassPtr := ClassType; //獲得初始化標(biāo)的地址 InitTable := PPointer(Integer(ClassPtr) + vmtInitTable)^; //如果當(dāng)前類存在 并且初始化表也存在 while (ClassPtr <> nil) and (InitTable <> nil) do begin //釋放所有的信息 _FinalizeRecord(Self, InitTable); //如果當(dāng)前類有父類 則清楚父類的信息 ClassPtr := ClassPtr.ClassParent; if ClassPtr <> nil then InitTable := PPointer(Integer(ClassPtr) + vmtInitTable)^; end; end; //獲得當(dāng)前類的類型 function TObject.ClassType: TClass; begin //就是返回當(dāng)前類的指針 Pointer(Result) := PPointer(Self)^; end; //獲得當(dāng)前類的類名 class function TObject.ClassName: ShortString; {$IFDEF PUREPASCAL} begin //根據(jù)虛擬方發(fā)表返回指定的地址 Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^; end; // 判斷當(dāng)前類的類名 class function TObject.ClassNameIs(const Name: string): Boolean; {$IFDEF PUREPASCAL} var Temp: ShortString; I: Byte; begin Result := False; //獲得當(dāng)前類的類名得指針 Temp := ClassName; //根據(jù)字符串的長(zhǎng)度比較每個(gè)字符 區(qū)分大小寫 for I := 0 to Byte(Temp[0]) do if Temp[I] <> Name[I] then Exit; Result := True; end; //獲得當(dāng)前類的父類 class function TObject.ClassParent: TClass; {$IFDEF PUREPASCAL} begin //根據(jù)虛擬方法表或的父的地址指針 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; //獲得實(shí)列大小 class function TObject.InstanceSize: Longint; begin Result := PInteger(Integer(Self) + vmtInstanceSize)^; end; //判斷是否從一個(gè)類繼承下來 class function TObject.InheritsFrom(AClass: TClass): Boolean; {$IFDEF PUREPASCAL} var ClassPtr: TClass; begin ClassPtr := Self; //當(dāng)前類是否存在 并且和比較的類不等 while (ClassPtr <> nil) and (ClassPtr <> AClass) do //獲得這個(gè)類的父類 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; //根據(jù)方法名稱獲得地址 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] //獲得字符串的長(zhǎng)度 JMP @@haveVMT //判斷是否有虛擬方發(fā)表 @@outer: { upper 16 bits of ECX are 0 ! } MOV EAX,[EAX] @@haveVMT: MOV ESI,[EAX].vmtMethodTable //獲得虛擬方發(fā)表的地址 TEST ESI,ESI //是否存在 JE @@parent //如果不存在 MOV DI,[ESI] { EDI := method count }方法的數(shù)量 ADD ESI,2 // 開始 @@inner: { upper 16 bits of ECX are 0 ! } MOV CL,[ESI+6] { compare length of strings } //獲得名城的長(zhǎng)度 CMP CL,BL //比較長(zhǎng)度 JE @@cmpChar //如果相等就開始比較字符 @@cont: { upper 16 bits of ECX are 0 ! } MOV CX,[ESI] { fetch length of method desc } //獲得方法的長(zhǎng)度 //長(zhǎng)度兩個(gè)字節(jié) 指針4個(gè)字節(jié) /// ADD ESI,ECX { point ESI to next method } //指向下一個(gè)函數(shù) DEC EDI JNZ @@inner @@parent: //獲得父的方發(fā)表 MOV EAX,[EAX].vmtParent { fetch parent vmt } TEST EAX,EAX //是否為0 JNE @@outer //不為零 JMP @@exit { return NIL } //已經(jīng)到根 @@notEqual: MOV BL,[EDX] { restore BL to length of name } //存儲(chǔ)名字的長(zhǎng)度 JMP @@cont //轉(zhuǎn)移 @@cmpChar: { upper 16 bits of ECX are 0 ! } MOV CH,0 { upper 24 bits of ECX are 0 ! } ///清空高位字節(jié) @@cmpCharLoop: MOV BL,[ESI+ECX+6] { case insensitive string cmp } //獲得第一個(gè)字符 XOR BL,[EDX+ECX+0] { last char is compared first } //比較 AND BL,$DF //清空其他標(biāo)志位 JNE @@notEqual DEC ECX { ECX serves as counter } //比較下一個(gè) JNZ @@cmpCharLoop //如果不為零 進(jìn)行下一個(gè)字符的比較 { found it } MOV EAX,[ESI+2] //找到 并且得到指針 12 方法長(zhǎng)度 3456 方法指針 7890 方法名稱 7 方法名城的長(zhǎng)度 @@exit: POP EDI POP ESI POP EBX end; //根據(jù)字段名獲得地址 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的長(zhǎng)度 PUSH EAX { save instance pointer } //保存當(dāng)前實(shí)列指針 @@outer: MOV EAX,[EAX] { fetch class pointer } //獲得當(dāng)前類的指針 MOV ESI,[EAX].vmtFieldTable //獲得字段列表的地址 TEST ESI,ESI //是否存在 JE @@parent //如果不存在就到當(dāng)前的父類查找 MOV DI,[ESI] { fetch count of fields } //獲得字段的數(shù)量 ADD ESI,6 // 2 為數(shù)量 4 位指針 @@inner: MOV CL,[ESI+6] { compare string lengths } //獲得當(dāng)前字段的長(zhǎng)度 CMP CL,BL //比較長(zhǎng)度 JE @@cmpChar //如果相等 就開始比較 字符 @@cont: ///LEA是取變量的地址 LEA ESI,[ESI+ECX+7] { point ESI to next field } //Esi指向下一個(gè)字段ESI 當(dāng)前位子+ECX 長(zhǎng)度+7 ??? DEC EDI //數(shù)量減一 JNZ @@inner //如果不等于零則繼續(xù)比較 @@parent: MOV EAX,[EAX].vmtParent { fetch parent VMT } //獲得當(dāng)前的父類地址 TEST EAX,EAX //是否存在 JNE @@outer //如果存在則準(zhǔn)備獲得字段數(shù)量 POP EDX { forget instance, return Nil } //否則恢復(fù)Edx 恢復(fù)實(shí)列 返回nil 當(dāng)前Eax為空 JMP @@exit //并且退出 @@notEqual: MOV BL,[EDX] { restore BL to length of name } //獲得目的字段名稱的長(zhǎng)度 MOV CL,[ESI+6] { ECX := length of field name } //獲得源字段名城的長(zhǎng)度 JMP @@cont @@cmpChar: MOV BL,[ESI+ECX+6] { case insensitive string cmp } //字符比較 XOR BL,[EDX+ECX+0] { starting with last char } AND BL,$DF //標(biāo)志位處理 JNE @@notEqual //如果不等 DEC ECX { ECX serves as counter } //字符長(zhǎng)度減一 JNZ @@cmpChar //如果還有沒有比較完的字符 { found it } MOV EAX,[ESI] { result is field offset plus ... } //獲得當(dāng)前的地址的偏移量 POP EDX //恢復(fù)當(dāng)前實(shí)列到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; ---------------------- 一個(gè)實(shí)列的創(chuàng)建過程 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 } 一個(gè)類實(shí)例的生成需要經(jīng)過對(duì)象內(nèi)存分配、內(nèi)存初始化、設(shè)置對(duì)象執(zhí)行框架三個(gè)步驟。 編譯器首先調(diào)用 System._ClassCreate 進(jìn)行對(duì)象內(nèi)存分配、內(nèi)存初始化的工作。而 System._ClassCreate 調(diào)用 TObject 類的虛方法 NewInstance 建立對(duì)象的實(shí)例空間,繼承類通常不需要重載 TObject.NewInstance,除非你使用自己的內(nèi)存管理器,因此缺省是調(diào)用 TObject.NewInstance。TObject.NewInstance 方法將根據(jù)編譯器在類信息數(shù)據(jù)中初始化的對(duì)象實(shí)例尺寸(TObject.InstanceSize),調(diào)用系統(tǒng)缺省的 MemoryManager.GetMem 過程為該對(duì)象在堆(Heap)中分配內(nèi)存,然后調(diào)用 TObject.InitInstance 方法將分配的空間初始化。InitInstance 方法首先將對(duì)象空間的頭4個(gè)字節(jié)初始化為指向?qū)ο箢惖?VMT 的指針,然后將其余的空間清零。如果類中還設(shè)計(jì)了接口,它還要初始化接口表格(Interface Table)。 當(dāng)對(duì)象實(shí)例在內(nèi)存中分配且初始化后,開始設(shè)置執(zhí)行框架。所謂設(shè)置執(zhí)行框架就是執(zhí)行你在 Create 方法里真正寫的代碼。設(shè)置執(zhí)行框架的規(guī)矩是先設(shè)置基類的框架,然后再設(shè)置繼承類的,通常用 Inherited 關(guān)鍵字來實(shí)現(xiàn)。 上述工作都做完后,編譯器還要調(diào)用 System._AfterConstruction 讓你有最后一次機(jī)會(huì)進(jìn)行一些事務(wù)的處理工作。System._AfterConstruction 是調(diào)用虛方法 AfterConstruction 實(shí)現(xiàn)的。 在 TObject 中 AfterConstruction 中只是個(gè) Place Holder,你很少需要重載這個(gè)方法,重載這個(gè)方法通常只是為了與 C++ Builder 對(duì)象模型兼容。 最后,編譯器返回對(duì)象實(shí)例數(shù)據(jù)的地址指針。 對(duì)象釋放服務(wù)其實(shí)就是對(duì)象創(chuàng)建服務(wù)的逆過程,可以認(rèn)為對(duì)象釋放服務(wù)就是回收對(duì)象在創(chuàng)建過程中分配的資源。 當(dāng)編譯器遇到 destructor 關(guān)鍵字通常會(huì)這樣編碼:首先調(diào)用 System._BeforeDestruction,而 System._BeforeDestruction 繼而調(diào)用虛方法 BeforeDestruction, 在 TObject 中 BeforeDestruction 中只是個(gè) Place Holder,你很少需要重載這個(gè)方法,重載這個(gè)方法通常只是為了與 C++ Builder 對(duì)象模型兼容。 這之后,編譯器調(diào)用你在 Destroy 中真正寫的代碼,如果當(dāng)前你在撰寫的類是繼承鏈上的一員,不要忘記通過 inherited 調(diào)用父類的析構(gòu)函數(shù)以釋放父類分配的資源,但規(guī)矩是,先釋放當(dāng)前類的資源,然后再調(diào)用父類的,這和對(duì)象創(chuàng)建服務(wù)中設(shè)置對(duì)象執(zhí)行框架的順序恰好相反。 當(dāng)前類及繼承鏈中所有類中分配的資源全部釋放后,最后執(zhí)行的就是釋放掉對(duì)象本身及一些特別數(shù)據(jù)類型占用的內(nèi)存空間。編譯器調(diào)用 System._ClassDestroy 來完成這件工作。System._ClassDestroy 繼而調(diào)用虛方法 FreeInstance,繼承類通常不需要重載 TObject.FreeInstance,除非你使用自己的內(nèi)存管理器,因此缺省是調(diào)用 TObject.FreeInstance。TObject.FreeInstance 繼而調(diào)用 TObject.CleanupInstance 完成對(duì)于字符串?dāng)?shù)組、寬字符串?dāng)?shù)組、Variant、未定義類型數(shù)組、記錄、接口和動(dòng)態(tài)數(shù)組這些特別數(shù)據(jù)類型占用資源的釋放[4],最后 TObject.FreeInstance 調(diào)用 MemoryManager.FreeMem 釋放對(duì)象本身占用的內(nèi)存空間。 很有意思的是,對(duì)象釋放服務(wù)與對(duì)象創(chuàng)建服務(wù)所用方法、函數(shù)是一一對(duì)應(yīng)的,是不是有一種很整齊的感覺? 對(duì)象創(chuàng)建服務(wù) 對(duì)象釋放服務(wù) 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 還有一點(diǎn)要注意,通常我們不會(huì)直接調(diào)用 Destroy 來釋放對(duì)象,而是調(diào)用 TObject.Free,它會(huì)在釋放對(duì)象之前檢查對(duì)象引用是否為 nil。

總結(jié)

以上是生活随笔為你收集整理的TObject简要说明-对象的创建流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。