早点睡觉 發表於 2020-5-9 14:06:00

Delphi Class的构造和析构顺序

<p>本文转载https://www.cnblogs.com/findumars/p/5037487.html</p>
<p>&nbsp;</p>
<p>1:&nbsp; Class&nbsp;destructor 类析构函数前加了Class,当前类的析构函数在程序结束后会自己调用析构函数,无需手动析构。</p>
<p>2:&nbsp; 通过代码演示Class的构造和析构顺序</p>
<p>&nbsp;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">unit Unit2;

interface

Type
TClassTest = class
    class constructor create();
    class destructor destory();
end;

implementation
uses
Windows;

{ TClassTest }

class constructor TClassTest.create;
begin
OutputDebugString('class constructor');
end;

class destructor TClassTest.destory;
begin
OutputDebugString('class destructor');
end;

initialization
   OutputDebugString('Unit initialization');
finalization
   OutputDebugString('Unit finalization');

end.

为了防止编译器因为TClassTest 没有被使用而优化去掉TClassTest .所以我们要用一下TClassTest .

procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := TClassTest.ClassName;

end;
</pre>
</div>
<p>运行,然后退出.在Event Log窗口中我们见到.</p>
<p>可见类的构造是在Unit初始化前被调用,而类的析构则是在Unit的反初始化后被调用的.</p>
<p>Debug Output: class constructor Process Project1.exe (3940)<br>Debug Output: Unit initialization Process Project1.exe (3940)<br>Debug Output: Unit finalization Process Project1.exe (3940)<br>Debug Output: class destructor Process Project1.exe (3940)</p>
<p>&nbsp;</p>
<p>进而再看如果是有派生类,祖先类的情况.</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">unit Unit2;

interface

Type

TClassTestParent = class
    class constructor create();
    class destructor destory();
end;

TClassTest = class(TClassTestParent)
    class constructor create();
    class destructor destory();
end;

implementation
uses
Windows;

{ TClassTest }

class constructor TClassTest.create;
begin
OutputDebugString('class constructor');
end;

class destructor TClassTest.destory;
begin
OutputDebugString('class destructor');
end;

{ TClassTestParent }

class constructor TClassTestParent.create;
begin
OutputDebugString('Parent class constructor');
end;

class destructor TClassTestParent.destory;
begin
OutputDebugString('Parent class destructor');
end;

initialization
   OutputDebugString('Unit initialization');
finalization
   OutputDebugString('Unit finalization');

end.
</pre>
</div>
<p>那么结果是:</p>
<p>Debug Output: Parent class constructor Process Project1.exe (3256)<br>Debug Output: class constructor Process Project1.exe (3256)<br>Debug Output: Unit initialization Process Project1.exe (3256)<br>Debug Output: Unit finalization Process Project1.exe (3256)<br>Debug Output: class destructor Process Project1.exe (3256)<br>Debug Output: Parent class destructor Process Project1.exe (3256)</p>
<p>可见如果存在类的继承关系则规律是</p>
<p>先父类的构造,然后是子类的构造,最后是单元初始化;先单元反初始化,然后是子类析构,最后是父类析构.</p>
<p>然后再进一步测试:</p>
<p>&nbsp; TClassTestA = class<br>&nbsp; public<br>&nbsp;&nbsp;&nbsp; class constructor create();<br>&nbsp;&nbsp;&nbsp; class destructor destory();<br>&nbsp; end;</p>
<p>&nbsp; TClassTestB = class<br>&nbsp;&nbsp;&nbsp; class constructor create();<br>&nbsp;&nbsp;&nbsp; class destructor destory();<br>&nbsp; end;</p>
<p>发现同一个单元内多个不相干的类,似乎是后面的类构造函数是和声明次序相反的.析构则是和声明顺序相同</p>
<p>再进一步测试</p>
<p>改造如下代码:</p>
<p>class constructor TClassTestB.create;<br>begin<br>&nbsp; if(TClassTestA.ClassName = '') then<br>&nbsp; else<br>&nbsp; OutputDebugString('class B constructor');<br>end;</p>
<p>发现如果一个类的构造中使用了另外的类,那么构造顺序则是先调用被引用类的构造.</p>
<p>这时想起一个有趣的问题,如果循环使用的话会是什么结果呢.我的猜测是或许编译器不会让通过吧.</p>
<p>class constructor TClassTestB.create;<br>begin<br>&nbsp; if(TClassTestA.ClassName = '') then<br>&nbsp; else<br>&nbsp; OutputDebugString('class B constructor');<br>end;</p>
<p>class constructor TClassTestA.create;<br>begin<br>&nbsp; if(TClassTestB.ClassName = '') then<br>&nbsp; else<br>&nbsp; OutputDebugString('class A constructor');<br>end;</p>
<p>嘿嘿,出乎我的意料.编译竟然通过了.结果是类构造函数循环使用其他的类的话又变成按声明顺序调用类构造函数,按声明顺序相反顺序调用类的析构函数.</p>
<p>&nbsp;</p>
<p>最后的规律就是:</p>
<p>1.类析构顺序总是和类构造顺序相反,类的构造总是在单元初始化前被调用.类的析构器总是在单元的反初始化后被调用</p>
<p>2.无关联的情况下按声明的顺序相反调用类构造</p>
<p>3.优先调父类的类构造函数</p>
<p>4.优先调用在类构造析构器中被使用的其他类的类构造</p>
<p>5.如果在类构造析构器循环使用的话按声明的顺序调用类构造器</p>
<p>可能还有其他规律吧.</p>
<p>同时有个额外发现.如果类有构造器析构器的话Delphi编译器的代码提示会有一个诸如TClassTestA.$ClassInitFlag之类的变量提示出来.</p>
<p>而正常的类则不会有这个提示.当然这个东西肯定是不能在代码中使用的,因为"$"在变量名函数名中都是非法的符号.应该是编译器产生的一些符号表标志被提示出来了</p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/sttchengfei/p/12857094.html
頁: [1]
查看完整版本: Delphi Class的构造和析构顺序