发了上一篇博客.盒子上有朋友认为Class的构造和析构延迟加载.是在Unit的初始化后调用的Class的构造.在Unit的反初始化前调用的Class的析构函数.

为了证明一下我又做了个试验

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;

运行,然后退出.在Event Log窗口中我们见到.

可见类的构造是在Unit初始化前被调用,而类的析构则是在Unit的反初始化后被调用的.

Debug Output: class constructor Process Project1.exe (3940)
Debug Output: Unit initialization Process Project1.exe (3940)
Debug Output: Unit finalization Process Project1.exe (3940)
Debug Output: class destructor Process Project1.exe (3940)

进而再看如果是有派生类,祖先类的情况.

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.
那么结果是:

Debug Output: Parent class constructor Process Project1.exe (3256)
Debug Output: class constructor Process Project1.exe (3256)
Debug Output: Unit initialization Process Project1.exe (3256)
Debug Output: Unit finalization Process Project1.exe (3256)
Debug Output: class destructor Process Project1.exe (3256)
Debug Output: Parent class destructor Process Project1.exe (3256)

可见如果存在类的继承关系则规律是

先父类的构造,然后是子类的构造,最后是单元初始化;先单元反初始化,然后是子类析构,最后是父类析构.

然后再进一步测试:

TClassTestA = class
  public
    class constructor create();
    class destructor destory();
  end;

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

发现同一个单元内多个不相干的类,似乎是后面的类构造函数是和声明次序相反的.析构则是和声明顺序相同

再进一步测试

改造如下代码:

class constructor TClassTestB.create;
begin
  if(TClassTestA.ClassName = '') then
  else
  OutputDebugString('class B constructor');
end;

发现如果一个类的构造中使用了另外的类,那么构造顺序则是先调用被引用类的构造.

这时想起一个有趣的问题,如果循环使用的话会是什么结果呢.我的猜测是或许编译器不会让通过吧.

class constructor TClassTestB.create;
begin
  if(TClassTestA.ClassName = '') then
  else
  OutputDebugString('class B constructor');
end;

class constructor TClassTestA.create;
begin
  if(TClassTestB.ClassName = '') then
  else
  OutputDebugString('class A constructor');
end;

嘿嘿,出乎我的意料.编译竟然通过了.结果是类构造函数循环使用其他的类的话又变成按声明顺序调用类构造函数,按声明顺序相反顺序调用类的析构函数.

最后的规律就是:

1.类析构顺序总是和类构造顺序相反,类的构造总是在单元初始化前被调用.类的析构器总是在单元的反初始化后被调用

2.无关联的情况下按声明的顺序相反调用类构造

3.优先调父类的类构造函数

4.优先调用在类构造析构器中被使用的其他类的类构造

5.如果在类构造析构器循环使用的话按声明的顺序调用类构造器

可能还有其他规律吧.

同时有个额外发现.如果类有构造器析构器的话Delphi编译器的代码提示会有一个诸如TClassTestA.$ClassInitFlag之类的变量提示出来.

而正常的类则不会有这个提示.当然这个东西肯定是不能在代码中使用的,因为"$"在变量名函数名中都是非法的符号.应该是编译器产生的一些符号表标志被提示出来了.呵呵.

http://blog.csdn.net/wr960204/article/details/4525763

再探Delphi2010 Class的构造和析构顺序的更多相关文章

  1. C++浅析——继承类中构造和析构顺序

    先看测试代码,CTEST 继承自CBase,并包含一个CMember成员对象: static int nIndex = 1; class CMember { public: CMember() { p ...

  2. C++ //继承中构造和析构顺序

    1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 pu ...

  3. C++语法小记---继承中的构造和析构顺序

    继承中构造和析构的顺序 先父母,后客人,最后自己 静态变量和全局变量在最开始 析构和构造的顺序完全相反 #include <iostream> #include <string> ...

  4. C++ 类成员的构造和析构顺序

    我想对面向对象有了解的童鞋应该不会对类和对象感到陌生吧 ! 对象并不是突然建立起来的,创建对象必须时必须同时创建父类以及包含于其中的对象.C++遵循如下的创建顺序: (1)如果某个类具体基类,执行基类 ...

  5. C++构造和析构的顺序

    C++构造函数和析构函数的顺序 #include <iostream> using namespace std; class CA {public: CA() { cout << ...

  6. C++中的析构顺序和cosnt对象

    1,当程序中存在多个对象的时候,如何确定这些对象的析构顺序? 2,单个对象创建时构造函数的调用顺序(工程经验总结): 1,调用父类的构造过程: 2,调用成员变量的构造函数(调用顺序与声明顺序相同): ...

  7. c++之——派生类的同名成员和函数调用方式及构造析构顺序

    #include<iostream> using namespace std; class Object { public: Object(), b(), c() { cout <& ...

  8. c++再探string之eager-copy、COW和SSO方案

    在牛客网上看到一题字符串拷贝相关的题目,深入挖掘了下才发现原来C++中string的实现还是有好几种优化方法的. 原始题目是这样的: 关于代码输出正确的结果是()(Linux g++ 环境下编译运行) ...

  9. 【再探backbone 02】集合-Collection

    前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...

随机推荐

  1. 什么是Web前端,Web前端是做什么的?

    什么是Web前端 Web前端,顾名思义是来做Web的前端的.而Web前端开发应该就是来开发基于Web前端的相关应用的或者说是来开发前端的.那么,前端又是什么呢?我们这里所说的前端泛指Web前端,也就是 ...

  2. 浏览器间bug

    转自:http://www.cnblogs.com/yexiaochai/archive/2013/06/10/3130632.html 1.IE7的bug 就是z-index需要依赖其父元素的z-i ...

  3. Spring简单的文件配置

    Spring简单的文件配置 “计应134(实验班) 凌豪” 一.Spring文件配置 spring至关重要的一环就是装配,即配置文件的编写,接下来我按刚才实际过程中一步步简单讲解. 首先,要在web. ...

  4. ODI中删除数据的处理

    ODI中删除数据的处理 一.前提知识:数据从源数据库向数据仓库抽取时,一般采用以下几种方式: 全抽取模式如果表的数据量较小,则可以采取全表抽取方式,以TRUNCATE/INSERT方式进行数据抽取. ...

  5. Sql Server数据库快照初探

    什么是快照 数据库快照是 SQL Server 数据库(源数据库)的只读静态视图.换句话说,快照可以理解为一个只读的数据库.利用快照,可以提供如下好处: 提供了一个静态的视图来为报表提供服务 可以利用 ...

  6. 如何在程序中动态设置墙纸(使用IActiveDesktop接口)

    大家都知道设置WINDOWS桌面墙纸的WIN32 API是SystemParametersInfo, 使用SPI_SETDESKWALLPAPER参数便能设置墙纸: ::SystemParameter ...

  7. Redis用户添加、分页、登录、注册、加关注案例

    连接redis代码redis.php <?php //实例化 $redis = new Redis(); //连接服务器 $redis->connect("localhost&q ...

  8. VC中实现带有背景位图的树型控件

    当前许多应用程序都在使用树型控件时为其添加了背景位图,增强的控件的魅力,然而对于Visual C++编程爱好者来说,使用Visual C++MFC提供的树型控件(CTreeCtrl)本身就是一个难点, ...

  9. java多线程向数据库写入数据

    任务: 从sqlserver中将一个表A(约16W条数据)导到mysql中对应的一个表B中. 思路:分段获取A表中的数据后,用多个线程同时向B表中写入. 关键代码 //将数据库中的数据条数分段 pub ...

  10. 通过iframe在其父窗口中打开隐藏元素

    先上代码 $(".login-box,#dl,.top_01 a:eq(1)").click(function(){ if(self!=top){ parent.$("# ...