dephi继承中的构造与析构

    在前段时间的学习中,了解了TObject对象的构造与析构基本流程,但是其中的一些细节问题并没有搞得很清楚,在阅读了“TObject.Create TComponent.Create之间的关系”【1】后,对于子类的构造与析构过程依旧不是太明白,于是我仔细的研究和分析了TObjectTPersistentTThreadListTComponent的构造和析构流程后,对于【1】的一些分析有了更多的认识,将在下面和大家分享。

         我们知道,在TObject的构造函数中,编译器调用了@ClassCreate@AfterConstruction两个函数,那么就有这样一个问题,当继承于TObject的类在构造时,若调用了inherited Create,编译器对@ClassCreate@AfterConstruction是怎样处理的呢?

         我们先来看TObject的构造代码,或许你从代码的标红就能猜到寄存器dl是问题解决的关键所在了,程序初始将dl设为1,而在Create中,通过dl的值来判断是否执行@ClassCreate@AfterConstructionTThreadList是继承于TObject的类,该类的构造函数调用了inherited Create,对应下面代码的粗体call TObject.Create,我们很容易看到,初始dl1,首先执行TThreadList@ClassCreate,随后,将dl置为零(xor edx,edx),从而跳过了TObject.Create中的ClassCreate调用,同样的道理,@AfterConstruction也只执行了一次。

         同样的方法,在析构过程中(可以参考TPersistentdestroy方法),通过dl的值来保证@ClassDestroy@BeforeDestruction只执行一次。

TObject

oTargetA := TObject.Create;

004BDC16 B201             mov dl,$01

004BDC18 A164114000       mov eax,[$00401164]

004BDC1D E8F65DF4FF       call TObject.Create

004BDC22 8945F8           mov [ebp-$08],eax

TObject.Create:

00403A18 84D2             test dl,dl

00403A1A 7408             jz $00403a24

00403A1C 83C4F0           add esp,-$10

00403A1F E888030000       call @ClassCreate

00403A24 84D2             test dl,dl

00403A26 740F             jz $00403a37

00403A28 E8D7030000       call @AfterConstruction

00403A2D 648F0500000000   pop dword ptr fs:[$00000000]

00403A34 83C40C           add esp,$0c

00403A37 C3               ret

 

TThreadList

oThreadList := TThreadList.Create;

004BDE40 B201             mov dl,$01

004BDE42 A1F8C04100       mov eax,[$0041c0f8]

004BDE47 E82010F6FF       call TThreadList.Create

 

TThreadList.Create:

……

0041EE6E 84D2             test dl,dl

0041EE70 7408             jz $0041ee7a

0041EE72 83C4F0           add esp,-$10

0041EE75 E8324FFEFF       call @ClassCreate

0041EE7A 8BDA            mov ebx,edx

0041EE7C 8BF0             mov esi,eax

0041EE7E 33D2             xor edx,edx

0041EE80 8BC6             mov eax,esi

0041EE82 E8914BFEFF       call TObject.Create

……

0041EEA5 84DB             test bl,bl

0041EEA7 740F             jz $0041eeb8

0041EEA9 E8564FFEFF       call @AfterConstruction

 

 

         由上面的分析可以看出编译器利用了一个寄存器dl来作为标识,处理继承中构造和析构的函数调用。通过比较TComponent构造函数的不同参数,我们发现编译器利用ecx作为参数传入TComponent.Create,保存在ESI作为标识,判断是否调用InsertComponent函数。

 

  1. constructor TComponent.Create(AOwner: TComponent);
  2. begin
  3.   FComponentStyle := [csInheritable];
  4.   if AOwner <> nil then AOwner.InsertComponent(Self);
  5. end;

 

TComponent

oComponent := TComponent.Create(nil);

004BDD1C 33C9             xor ecx,ecx

004BDD1E B201             mov dl,$01

004BDD20 A1B0CF4100       mov eax,[$0041cfb0]

004BDD25 E89A98F6FF       call TComponent.Create

004BDD2A 8945F8           mov [ebp-$08],eax

……

TComponent

oComponent := TComponent.Create(nil);

004BDDAF 8BCB             mov ecx,ebx

004BDDB1 B201             mov dl,$01

004BDDB3 A1B0CF4100       mov eax,[$0041cfb0]

004BDDB8 E80798F6FF       call TComponent.Create

 

 

  1. TComponent.Create:
  2. ……
  3. 004275D3 8BF1             mov esi,ecx
  4. 004275D5 8BDA             mov ebx,edx
  5. 004275D7 8BF8             mov edi,eax
  6. 004275D9 0FB6050C764200   movzx eax,[$0042760c]
  7. 004275E0 884724           mov [edi+$24],al
  8. 004275E3 85F6             test esi,esi
  9. 004275E5 7409             jz $004275f0
  10. 004275E7 8BD7             mov edx,edi
  11. 004275E9 8BC6             mov eax,esi
  12. 004275EB E890010000       call TComponent.InsertComponent

   

参考文献:

1TObject.Create TComponent.Create之间的关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值