zoukankan      html  css  js  c++  java
  • delphi 接口 对象 交叉引用-转


    (这个帖子,讲的内容,我没验证出来,没弄明白,只是留有以后参考,或许以后能理解)

    delphi 接口 对象 交叉引用

    delphi编程中有时会遇到类A,类B相互引用或者一方引用另一方的问题。这种问题无外乎以下几种做法。

    1.很多人可能都用过的,delphi下有两个地方可以uses其他单元,假如类A,B在不同的单元UnitA, UnitB且互相引用。一般UnitA interface uses UnitB; UnitB implementation UnitA,这样就可以了,不能同时在interfaceimplementation中互相引用,否则编译不过。这样虽然达到了目的,代码的耦合度非常高(单元相互引用)

    2.在其中一个定义函数原型,然后公布出来,让另一个实现。比如类A包含了类B(可以自由使用类B得可见接口),而类B想使用类A得接口,而UnitB是没有引用UnitA的,那么UnitB根本不知道有类A,如果对类B是少量的调用,可以在UnitB定义一些函数原型,然后类A实现这种原型的函数并将地址赋值给类B,这样类B可以调用自己的函数指正,无须知道A的情况。但若类B需要用到类A较多的接口时,这样做相当麻烦。

    3.使用delphi的接口。delphi的接口比较像c++的头文件。他定义的只是一套规则,实现的类必须严格依照规则,把办法交给了实现者,而不是调用者。这里类A将那些需要提供给其他类使用的方法做成一个interface,加入在单元UnitIA,接口名为IAA实现IAB引用UnitIA单元并定义外部可见的IA类型成员变量。类A在生成类B时将接口赋予类B,类就可以正常的调用类A得方法。类B在释放自己时必须先释放自己的成员变量类A,但由于接口的引用计数问题,编译器发现类B得引用计数不为0,触发异常,不予释放。假如释放过程成功,在释放类B得变量时由于导致类A得计数为0,将导致类A的实例被自动释放,继续执行类A得析构函数必定异常。

    IAIntf = interface

    ['{37BFA0BF-4952-47F8-AAB8-8FAAD36B0EE5}']

    procedure test;

    end;

    // B通过接口引用A

    TB = class

    private

    FIA: IAIntf; // A的接口

    public

    property IA: IAIntf read FIA write FIA;

    end;

    // BA的成员变量, 此类给外部使用,

    TA = class(TInterfacedObject, IAIntf)

    private

    FB: TB;

    public

    constructor Create;

    destructor Destroy; override;

     

    procedure test;

    end;//-----------------------------------------1----------------

    var

      A: TA;

     

    begin

     

       // 这样必定出错

     

      A := TA.Create;  // 此时A已被FB引用了一次

      //A.FB.IA := nil;  // 这样解除引用导致A被编译器释放(A.Destroy),下面的A.Free将触发异常

      A.Free;              // 由于BeforeDestruction判断RefCount<>0导致异常

    end;

     

     

     

    //------------------------------------2-----------------------------

     

    var

     

      A: TA;

     

      IA: AIntf;

    begin

      // 这种是可行的,声明A是为了看引用计数,可以构造后自己赋值给IA

      A := TA.Create;  // 此时A已被FB引用了一次

      IA := A;        // A被引用二次

      A.FB.IA := nil;  // FBA的引用解除,RefCount=1

      IA := nil;   // A的引用计数再次-1,编译器自动释放A

      // 到这里对象A已经被释放,不能再A.Free。或者上面的IA := nil不要也可以释放。

    end;

  • 相关阅读:
    Excutor线程池
    java-集合学习-底层实现
    java-接口—策略模式
    java开发技巧
    精进之道——为什么要问老师,不遮掩自己的弱点
    如何学习——为什么不想听课
    如何学习——如果差距过大怎么办
    Yii 之控制器响应
    Yii 之控制器创建使用
    PHP 之命名空间
  • 原文地址:https://www.cnblogs.com/luckForever/p/7255003.html
Copyright © 2011-2022 走看看