在前段时间的学习中,了解了TObject对象的构造与析构基本流程,但是其中的一些细节问题并没有搞得很清楚,在阅读了“TObject.Create 与TComponent.Create之间的关系”【1】后,对于子类的构造与析构过程依旧不是太明白,于是我仔细的研究和分析了TObject,TPersistent,TThreadList,TComponent的构造和析构流程后,对于【1】的一些分析有了更多的认识,将在下面和大家分享。
我们知道,在TObject的构造函数中,编译器调用了@ClassCreate和@AfterConstruction两个函数,那么就有这样一个问题,当继承于TObject的类在构造时,若调用了inherited Create,编译器对@ClassCreate和@AfterConstruction是怎样处理的呢?
我们先来看TObject的构造代码,或许你从代码的标红就能猜到寄存器dl是问题解决的关键所在了,程序初始将dl设为1,而在Create中,通过dl的值来判断是否执行@ClassCreate和@AfterConstruction。TThreadList是继承于TObject的类,该类的构造函数调用了inherited Create,对应下面代码的粗体call TObject.Create,我们很容易看到,初始dl为1,首先执行TThreadList的@ClassCreate,随后,将dl置为零(xor edx,edx),从而跳过了TObject.Create中的ClassCreate调用,同样的道理,@AfterConstruction也只执行了一次。
同样的方法,在析构过程中(可以参考TPersistent的destroy方法),通过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函数。
- constructor TComponent.Create(AOwner: TComponent);
- begin
- FComponentStyle := [csInheritable];
- if AOwner <> nil then AOwner.InsertComponent(Self);
- 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
|
- TComponent.Create:
- ……
- 004275D3 8BF1 mov esi,ecx
- 004275D5 8BDA mov ebx,edx
- 004275D7 8BF8 mov edi,eax
- 004275D9 0FB6050C764200 movzx eax,[$0042760c]
- 004275E0 884724 mov [edi+$24],al
- 004275E3 85F6 test esi,esi
- 004275E5 7409 jz $004275f0
- 004275E7 8BD7 mov edx,edi
- 004275E9 8BC6 mov eax,esi
- 004275EB E890010000 call TComponent.InsertComponent
参考文献:
1,TObject.Create 与TComponent.Create之间的关系