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;

posted @ 2013-10-22 15:57  Wishmeluck  阅读(546)  评论(0编辑  收藏  举报