再探Delphi2010 Class的构造和析构顺序
发了上一篇博客.盒子上有朋友认为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的构造和析构顺序的更多相关文章
- C++浅析——继承类中构造和析构顺序
先看测试代码,CTEST 继承自CBase,并包含一个CMember成员对象: static int nIndex = 1; class CMember { public: CMember() { p ...
- C++ //继承中构造和析构顺序
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class Base 6 { 7 pu ...
- C++语法小记---继承中的构造和析构顺序
继承中构造和析构的顺序 先父母,后客人,最后自己 静态变量和全局变量在最开始 析构和构造的顺序完全相反 #include <iostream> #include <string> ...
- C++ 类成员的构造和析构顺序
我想对面向对象有了解的童鞋应该不会对类和对象感到陌生吧 ! 对象并不是突然建立起来的,创建对象必须时必须同时创建父类以及包含于其中的对象.C++遵循如下的创建顺序: (1)如果某个类具体基类,执行基类 ...
- C++构造和析构的顺序
C++构造函数和析构函数的顺序 #include <iostream> using namespace std; class CA {public: CA() { cout << ...
- C++中的析构顺序和cosnt对象
1,当程序中存在多个对象的时候,如何确定这些对象的析构顺序? 2,单个对象创建时构造函数的调用顺序(工程经验总结): 1,调用父类的构造过程: 2,调用成员变量的构造函数(调用顺序与声明顺序相同): ...
- c++之——派生类的同名成员和函数调用方式及构造析构顺序
#include<iostream> using namespace std; class Object { public: Object(), b(), c() { cout <& ...
- c++再探string之eager-copy、COW和SSO方案
在牛客网上看到一题字符串拷贝相关的题目,深入挖掘了下才发现原来C++中string的实现还是有好几种优化方法的. 原始题目是这样的: 关于代码输出正确的结果是()(Linux g++ 环境下编译运行) ...
- 【再探backbone 02】集合-Collection
前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...
随机推荐
- 使用ConcurrentDictionary实现轻量缓存
项目中需要用到一个轻量缓存,存储重复使用的数据.在设计中需要考虑:1.做成通用组件,为未来其他模块方法操作结果做准备.2.缓存模块需要接口化,为未来替换使用外部缓存做准备.3.使用默认缓存过期时间,单 ...
- chrome实现全浏览器跨域ajax请求
如图,在chrome快捷方式上打开属性栏,在‘目标’栏加上后缀--disable-web-security --user-data-dir.即可实现在此浏览器上所有网页的跨域请求.
- 自定义Edit控件控制输入范围
//自定义Edit,实现十六进制输入控制,使用OnChar()函数实现 //MyEdit.h #pragma once class CMyEdit : public CEdit { DECLARE_D ...
- Oracle连接数过多释放机制
Oracle连接数过多释放机制 sqlplus /nolog 打开sqlplus connect /as sysdba 使用具有dba权限得用户登陆oracle ...
- [Drools]JAVA规则引擎 -- Drools 2
上一篇文章 http://blog.csdn.net/quzishen/archive/2011/01/25/6163012.aspx 描述了一些常用的drools的语法标签和一个模拟实例即发送积分的 ...
- Make Hadoop 1.2.1 run, my first try
经历两天努力,8月25日下午2点40分,终于让hadoop1.2.1跑起来. 用的是<Hadoop实战第2版>(陆嘉恒)里面的WordCount例子,虽然书是2013年出的,但用的例子还是 ...
- 初窥C++11:自己主动类型推导与类型获取
auto 话说C语言还处于K&R时代,也有auto a = 1;的写法.中文译过来叫自己主动变量.跟c++11的不同.C语言的auto a = 1;相当与 auto int a = 1;语句. ...
- VisualStudio中的代码段
VS很强大,在这里就不过多说了,在平时码代码时应用代码段会提高我们的编写速度. 举个例子: 比如输入Console.WriteLine (); 传统方法就是一个字母一个字母的输入进去. 如果大家掌握了 ...
- 简单的CSS网页布局--三列布局
三列布局其实不难,不过要用到position:absolute这个属性,因为这个属性是基于浏览器而言,左右部分各放在左右侧,空出中间一列来实现三列布局. (一)三列布局自适应 <!DOCTYPE ...
- 转 C#中静态方法与非静态方法区别比较
C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向你做一下解析. C#的类中可以包含两种方法:C#静态方法与非静态方法.那么他们的定义有什么不同呢?他们在使用 ...