• Delphi Class的构造和析构顺序


    本文转载https://www.cnblogs.com/findumars/p/5037487.html

    1:  Class destructor 类析构函数前加了Class,当前类的析构函数在程序结束后会自己调用析构函数,无需手动析构。

    2:  通过代码演示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之类的变量提示出来.

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

  • 相关阅读:
    彻底完全地被LINQ(2sql以及C#3.0里的一些语法)雷到了
    Windows界面设计标准
    对于大型公司项目平台选择j2ee的几层认识(四)
    用C#开发TUXEDO客户端
    提醒一下:XmlSerializer的效率比BinaryFormatter高!
    xml, oop, 云计算、web service,敏捷开发
    做了一个简单的DLINQ性能测试
    项目组的文档作风.
    RHEL 6和RHEL 7(CentOS 6和CentOS 7)恢复ROOT密码
    mysql修改root密码
  • 原文地址:https://www.cnblogs.com/sttchengfei/p/12857094.html
Copyright © 2020-2023  润新知