CnPack Forum » 技术板块灌水区 » [原创] 查询接口小议


2007-8-2 12:06 stanleyxu2005
[原创] 查询接口小议

原文地址:[url=http://blog.csdn.net/Stanley_Xu/archive/2007/08/02/1722313.aspx]http://blog.csdn.net/Stanley_Xu/archive/2007/08/02/1722313.aspx[/url]


[b][font="][size=10pt]前面的废话[/size][/font][/b][b][font="][size=10pt][/size][/font][/b]
[font="][size=10pt]接口大大增强了类设计的灵活性,类似于[/size][/font][font="][size=10pt]c++[/size][/font][font="][size=10pt]中的多重继承。[/size][/font][font="][size=10pt]不管你是否真正了解接口[/size][/font][font="][size=10pt] (Interface)[/size][/font][font="][size=10pt],但它已经默默的在为你的程序服务了。你可以去看一下[/size][/font][font="][size=10pt] TComponent [/size][/font][font="][size=10pt]的定义部分,你会发现它内部已经封装了[/size][/font][font="][size=10pt]2[/size][/font][font="][size=10pt]个接口:[/size][/font][font="][size=10pt]IInterface,IInterfaceComponentReference[/size][/font][font="][size=10pt]。[/size][/font][font="][size=10pt]不难发现,[/size][/font][font="][size=10pt]Delphi [/size][/font][font="][size=10pt]中除了原子类 [/size][/font][font="][size=10pt]TObject [/size][/font][font="][size=10pt]之外,任何[/size][/font][font="][size=10pt]类有且只有一个父类,但同时它可以拥有[/size][/font][font="][size=10pt]0..n[/size][/font][font="][size=10pt]个接口。接口是一组抽象的函数集,不能被实例化,函数实现部分必须由它的实现类或间接实现[/size][/font][font="][size=10pt] ([/size][/font][font="][size=10pt]外包[/size][/font][font="][size=10pt]) [/size][/font][font="][size=10pt]类完成。[/size][/font][font="][size=10pt][/size][/font]
[b][font="][size=10pt] [/size][/font][/b]
[b][font="][size=10pt]如何查询接口[/size][/font][/b][b][font="][size=10pt][/size][/font][/b]
[font="][size=10pt]先请看下面的代码:[/size][/font][font="][size=10pt][/size][/font]
[b][font="][size=9pt]type[/size][/font][/b][font="][size=9pt]
  IHello = [/size][/font][b][font="][size=9pt]interface[/size][/font][/b][font="][size=9pt](IUnknown)
    [[/size][/font][font="][size=9pt]'{1EE7A0AA-F525-4DD5-AB1B-900348BF8322}'[/size][/font][font="][size=9pt]]
    [/size][/font][b][font="][size=9pt]procedure[/size][/font][/b][font="][size=9pt] Hello;
  [/size][/font][b][font="][size=9pt]end[/size][/font][/b][font="][size=9pt];
  
  THello = [/size][/font][b][font="][size=9pt]class[/size][/font][/b][font="][size=9pt](TObject, IHello)
    [/size][/font][font="][size=9pt]// Implements IHello[/size][/font][font="][size=9pt]
    [/size][/font][b][font="][size=9pt]procedure[/size][/font][/b][font="][size=9pt] Hello;
  [/size][/font][b][font="][size=9pt]end[/size][/font][/b][font="][size=9pt];

[/size][/font][b][font="][size=9pt]procedure[/size][/font][/b][font="][size=9pt] UnSafeInftCall(Obj: TObject);
[/size][/font][b][font="][size=9pt]begin[/size][/font][/b][font="][size=9pt]
  [/size][/font][font="][size=9pt]// Case 1[/size][/font][font="][size=9pt]
  Obj.Hello; [/size][/font][font=&quot;][size=9pt]//<-- Syntax error[/size][/font][font=&quot;][size=9pt]
  [/size][/font][font=&quot;][size=9pt]// Case 2[/size][/font][font=&quot;][size=9pt]
  THello(Obj).Hello;
  [/size][/font][font=&quot;][size=9pt]// Case 3[/size][/font][font=&quot;][size=9pt]
  IHello(Obj).Hello;
[/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];

[/size][/font][b][font=&quot;][size=9pt]procedure[/size][/font][/b][font=&quot;][size=9pt] SafeInftCall(Obj: TObject);
[/size][/font][b][font=&quot;][size=9pt]var[/size][/font][/b][font=&quot;][size=9pt]
  pIntfHello: IHello;
[/size][/font][b][font=&quot;][size=9pt]begin[/size][/font][/b][font=&quot;][size=9pt]
  [/size][/font][font=&quot;][size=9pt]// Case 4[/size][/font][font=&quot;][size=9pt]
  [/size][/font][b][font=&quot;][size=9pt]if[/size][/font][/b][font=&quot;][size=9pt] Obj.GetInterface(IHello, pIntfHello) [/size][/font][b][font=&quot;][size=9pt]then[/size][/font][/b][font=&quot;][size=9pt]
    pIntfHello.Hello;
  [/size][/font][font=&quot;][size=9pt]// Case 5[/size][/font][font=&quot;][size=9pt]
  [/size][/font][b][font=&quot;][size=9pt]try[/size][/font][/b][font=&quot;][size=9pt]
    pIntfHello := Obj [/size][/font][b][font=&quot;][size=9pt]as[/size][/font][/b][font=&quot;][size=9pt] IHello;
    pIntfHello.Hello;
  [/size][/font][b][font=&quot;][size=9pt]except[/size][/font][/b][font=&quot;][size=9pt] [/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];
  [/size][/font][font=&quot;][size=9pt]// Case 6[/size][/font][font=&quot;][size=9pt]
  [/size][/font][b][font=&quot;][size=9pt]if[/size][/font][/b][font=&quot;][size=9pt] Supports(Obj, IHello, pIntfHello) [/size][/font][b][font=&quot;][size=9pt]then[/size][/font][/b][font=&quot;][size=9pt]
    pIntfHello.Hello;
[/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];[/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[font=&quot;][size=10pt]前面[/size][/font][font=&quot;][size=10pt]3[/size][/font][font=&quot;][size=10pt]种情况都是不安全的接口函数调用,这里就不仔细说了。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]情况[/size][/font][font=&quot;][size=10pt]4[/size][/font][font=&quot;][size=10pt]:这种方法是最直接的。[/size][/font][font=&quot;][size=10pt]GetInterface [/size][/font][font=&quot;][size=10pt]函数会去[/size][/font][font=&quot;][size=10pt] VMT [/size][/font][font=&quot;][size=10pt]中寻找是否定义过 [/size][/font][font=&quot;][size=10pt]IHello [/size][/font][font=&quot;][size=10pt]这个接口,如果找到的话,并且把实现者的实例返回到[/size][/font][font=&quot;][size=10pt] pIntfHello [/size][/font][font=&quot;][size=10pt]中。这样就可以安全的使用了。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]情况[/size][/font][font=&quot;][size=10pt]5[/size][/font][font=&quot;][size=10pt]:这里使用了保留字[/size][/font][font=&quot;][size=10pt] as [/size][/font][font=&quot;][size=10pt]进行强制类型转换。如果转换失败运行期会丢出异常,我们可以通过[/size][/font][font=&quot;][size=10pt] try…except [/size][/font][font=&quot;][size=10pt]处理掉异常。其实 [/size][/font][font=&quot;][size=10pt]as [/size][/font][font=&quot;][size=10pt]内部机制就是调用了[/size][/font][font=&quot;][size=10pt] _IntfCast[/size][/font][font=&quot;][size=10pt],只是比情况[/size][/font][font=&quot;][size=10pt]4 [/size][/font][font=&quot;][size=10pt]多了一个抛出异常而已。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]情况[/size][/font][font=&quot;][size=10pt]6[/size][/font][font=&quot;][size=10pt]:可以通过[/size][/font][font=&quot;][size=10pt]Supports [/size][/font][font=&quot;][size=10pt]函数查询接口。于情况[/size][/font][font=&quot;][size=10pt]4[/size][/font][font=&quot;][size=10pt]不同的是[/size][/font][font=&quot;][size=10pt] Supports [/size][/font][font=&quot;][size=10pt]会自动检查[/size][/font][font=&quot;][size=10pt] Obj [/size][/font][font=&quot;][size=10pt]是否是个有效的实例,帮你省了一行代码。(但是这个函数会让你在接口转换时付出其它额外的代价)[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[b][font=&quot;][size=10pt]使用[/size][/font][/b][b][font=&quot;][size=10pt] Supports [/size][/font][/b][b][font=&quot;][size=10pt]的[/size][/font][/b][b][font=&quot;][size=10pt]2[/size][/font][/b][b][font=&quot;][size=10pt]个问题[/size][/font][/b][b][font=&quot;][size=10pt][/size][/font][/b]
[font=&quot;][size=10pt]这个问题的发现实出偶然:网友许子健设计的一个接口应用中统一使用了[/size][/font][font=&quot;][size=10pt] as 进行转换,而我当时推荐他使用 Supports,因为 Supports 在查询接口失败后并不抛异常,而是返回 False。虽然只是小小的代码改动,但是他的程序意外崩溃了。[/size][/font]
[font=&quot;][size=10pt]请看下面的代码[/size][/font][font=&quot;][size=10pt]:[/size][/font][font=&quot;][size=10pt][/size][/font]
[b][font=&quot;][size=9pt]type[/size][/font][/b][font=&quot;][size=9pt]
  THelloImplementor = [/size][/font][b][font=&quot;][size=9pt]class[/size][/font][/b][font=&quot;][size=9pt](TInterfacedObject, IHello)
  [/size][/font][b][font=&quot;][size=9pt]public[/size][/font][/b][font=&quot;][size=9pt]
    [/size][/font][b][font=&quot;][size=9pt]procedure[/size][/font][/b][font=&quot;][size=9pt] Hello;
  [/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];

[/size][/font][b][font=&quot;][size=9pt]procedure[/size][/font][/b][font=&quot;][size=9pt] TestMe;
[/size][/font][b][font=&quot;][size=9pt]var[/size][/font][/b][font=&quot;][size=9pt]
  Obj: THelloImplementor;
[/size][/font][b][font=&quot;][size=9pt]begin[/size][/font][/b][font=&quot;][size=9pt]
  Obj := THelloImplementor.Create;
  [/size][/font][b][font=&quot;][size=9pt]try[/size][/font][/b][font=&quot;][size=9pt]
    [/size][/font][b][font=&quot;][size=9pt]if[/size][/font][/b][font=&quot;][size=9pt] Supports(Obj, IHello) [/size][/font][b][font=&quot;][size=9pt]then[/size][/font][/b][font=&quot;][size=9pt] [/size][/font][font=&quot;][size=9pt]//<-- Obj.Destroy is called[/size][/font]
[b][font=&quot;][size=9pt]begin[/size][/font][/b][font=&quot;][size=9pt]
      [/size][/font][font=&quot;][size=9pt]//Own code[/size][/font]
[b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt]
  [/size][/font][b][font=&quot;][size=9pt]finally[/size][/font][/b][font=&quot;][size=9pt]
    ShowMessage(Obj.ClassName); [/size][/font][font=&quot;][size=9pt]//<-- Crashed![/size][/font][font=&quot;][size=9pt]
    Obj.Free;
  [/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];
[/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt]; [/size][/font][b][font=&quot;][size=9pt][/size][/font][/b]
[font=&quot;][size=10pt] [/size][/font]
[font=&quot;][size=10pt]奇怪吗,为什么用[/size][/font][font=&quot;][size=10pt] Supports 查询接口出错了呢?通过调试发现,在执行Supports [/size][/font][font=&quot;][size=10pt]之后,[/size][/font][font=&quot;][size=10pt]Obj [/size][/font][font=&quot;][size=10pt]的实例被意外的释放了。于是乎意外应该是在[/size][/font][font=&quot;][size=10pt] Supports [/size][/font][font=&quot;][size=10pt]之内发生的。现在我们来看一下[/size][/font][font=&quot;][size=10pt]Supports [/size][/font][font=&quot;][size=10pt]的实现:[/size][/font][font=&quot;][size=10pt][/size][/font]
[b][font=&quot;][size=9pt]function[/size][/font][/b][font=&quot;][size=9pt] Supports([/size][/font][b][font=&quot;][size=9pt]const[/size][/font][/b][font=&quot;][size=9pt] Instance: TObject; [/size][/font][b][font=&quot;][size=9pt]const[/size][/font][/b][font=&quot;][size=9pt] IID: TGUID): Boolean; [/size][/font][b][font=&quot;][size=9pt]overload[/size][/font][/b][font=&quot;][size=9pt];
[/size][/font][b][font=&quot;][size=9pt]var[/size][/font][/b][font=&quot;][size=9pt]
  Temp: IInterface;
[/size][/font][b][font=&quot;][size=9pt]begin[/size][/font][/b][font=&quot;][size=9pt]
  Result := Supports(Instance, IID, Temp);
[/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[font=&quot;][size=10pt]当执行 [/size][/font][font=&quot;][size=10pt]Result := Supports(Instance, IID, Temp) 时,Temp 这个接口指针指向 Instance ([/size][/font][font=&quot;][size=10pt]即[/size][/font][font=&quot;][size=10pt]Obj),[/size][/font][font=&quot;][size=10pt]同时因为接口引用计数的关系[/size][/font][font=&quot;][size=10pt]Obj.FRefCount [/size][/font][font=&quot;][size=10pt]加一。当离开[/size][/font][font=&quot;][size=10pt]Supports [/size][/font][font=&quot;][size=10pt]函数时[/size][/font][font=&quot;][size=10pt],[/size][/font][font=&quot;][size=10pt]本地变量指针[/size][/font][font=&quot;][size=10pt]Temp [/size][/font][font=&quot;][size=10pt]会被清除[/size][/font][font=&quot;][size=10pt],[/size][/font][font=&quot;][size=10pt]于是[/size][/font][font=&quot;][size=10pt]Obj.FRefCount [/size][/font][font=&quot;][size=10pt]减一。[color=red]这个加一减一表面上没有差别,但是你完全无法预计[/color][/size][/font][font=&quot;][size=10pt] Instance [/size][/font][font=&quot;][size=10pt]内部会对[/size][/font][font=&quot;][size=10pt] FRefCount [/size][/font][font=&quot;][size=10pt]的变化做什么样的处理。[/size][/font][font=&quot;][size=10pt]而恰恰 [/size][/font][font=&quot;][size=10pt]Obj [/size][/font][font=&quot;][size=10pt]是从臭名昭著的 [/size][/font][font=&quot;][size=10pt]TInterfacedObject [/size][/font][font=&quot;][size=10pt]继承来的。这个类会当[/size][/font][font=&quot;][size=10pt] FRefCount=0 [/size][/font][font=&quot;][size=10pt]时释放掉实例本身。这个就是该程序出错的真正原因。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[font=&quot;][size=10pt]好了,下面再介绍一个隐藏的比较深的问题。这个和接口的委托机制有关。请看下面的代码[/size][/font][font=&quot;][size=10pt]:[/size][/font][font=&quot;][size=10pt][/size][/font]
[b][font=&quot;][size=9pt]type[/size][/font][/b][font=&quot;][size=9pt]
  TVirtualImplementor = [/size][/font][b][font=&quot;][size=9pt]class[/size][/font][/b][font=&quot;][size=9pt](TInterfacedObject[/size][/font][font=&quot;][size=9pt]{TObject does not have problem}[/size][/font][font=&quot;][size=9pt], IHello)
  [/size][/font][b][font=&quot;][size=9pt]public[/size][/font][/b][font=&quot;][size=9pt]
    FImplementorOfIHello: THelloImplementor;
    [/size][/font][b][font=&quot;][size=9pt]property[/size][/font][/b][font=&quot;][size=9pt] ImplementorOfIHello: THelloImplementor [/size][/font][b][font=&quot;][size=9pt]read[/size][/font][/b][font=&quot;][size=9pt]FImplementorOfIHello [/size][/font][b][font=&quot;][size=9pt]implements[/size][/font][/b][font=&quot;][size=9pt] IHello; [/size][/font][font=&quot;][size=9pt]//<--Be careful![/size][/font][font=&quot;][size=9pt]
  [/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];

[/size][/font][b][font=&quot;][size=9pt]procedure[/size][/font][/b][font=&quot;][size=9pt] TestMeAgain;
[/size][/font][b][font=&quot;][size=9pt]var[/size][/font][/b][font=&quot;][size=9pt]
  VI: TVirtualImplementor;
  pIntfHello: IHello;
[/size][/font][b][font=&quot;][size=9pt]begin[/size][/font][/b][font=&quot;][size=9pt]
  VI := TVirtualImplementor.Create;
  [/size][/font][b][font=&quot;][size=9pt]try[/size][/font][/b][font=&quot;][size=9pt]
    [/size][/font][font=&quot;][size=9pt]// Method 1[/size][/font][font=&quot;][size=9pt]
    [/size][/font][b][font=&quot;][size=9pt]try[/size][/font][/b][font=&quot;][size=9pt]
      pIntfHello := VI [/size][/font][b][font=&quot;][size=9pt]as[/size][/font][/b][font=&quot;][size=9pt] IHello;
      pIntfHello.Hello;
    [/size][/font][b][font=&quot;][size=9pt]except end[/size][/font][/b][font=&quot;][size=9pt];
    [/size][/font][font=&quot;][size=9pt]// Method 2[/size][/font][font=&quot;][size=9pt]
    [/size][/font][b][font=&quot;][size=9pt]if[/size][/font][/b][font=&quot;][size=9pt] Supports(VI, IHello, pIntfHello) [/size][/font][b][font=&quot;][size=9pt]then[/size][/font][/b][font=&quot;][size=9pt] [/size][/font][font=&quot;][size=9pt]//<-- VI.Destroy is called[/size][/font][font=&quot;][size=9pt]
      pIntfHello.Hello;
  [/size][/font][b][font=&quot;][size=9pt]finally[/size][/font][/b]
[font=&quot;][size=9pt]    ShowMessage(VI.ClassName);[/size][/font][font=&quot;][size=9pt]//<-- Crashed![/size][/font][font=&quot;][size=9pt]
    VI.Free;
  [/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];
[/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt]; [/size][/font][b][font=&quot;][size=9pt][/size][/font][/b]
[font=&quot;][size=10pt] [/size][/font]
[font=&quot;][size=10pt]如果使用[/size][/font][font=&quot;][size=10pt] as 做类型转换,程序是可以顺利运行的。但是为什么用Supports 就出错了呢?我们应该会很自然的联想上面那个问题。但问题是,这次接口指针 pIntfHello实实在在地获得了接口,而且在 VI 释放之前并没有清除,也就是说VI 不应该同上面的情况一样被自动销毁的。那么我们就再[/size][/font][font=&quot;][size=10pt]看一下[/size][/font][font=&quot;][size=10pt] Supports [/size][/font][font=&quot;][size=10pt]的实现:[/size][/font][font=&quot;][size=10pt][/size][/font]
[b][font=&quot;][size=9pt]function[/size][/font][/b][font=&quot;][size=9pt] Supports([/size][/font][b][font=&quot;][size=9pt]const[/size][/font][/b][font=&quot;][size=9pt] Instance: TObject; [/size][/font][b][font=&quot;][size=9pt]const[/size][/font][/b][font=&quot;][size=9pt] IID: TGUID; [/size][/font][b][font=&quot;][size=9pt]out[/size][/font][/b][font=&quot;][size=9pt] Intf): Boolean; [/size][/font][b][font=&quot;][size=9pt]overload[/size][/font][/b][font=&quot;][size=9pt];
[/size][/font][b][font=&quot;][size=9pt]var[/size][/font][/b][font=&quot;][size=9pt]
  LUnknown: IUnknown;
[/size][/font][b][font=&quot;][size=9pt]begin[/size][/font][/b][font=&quot;][size=9pt]
  Result := (Instance <> [/size][/font][b][font=&quot;][size=9pt]nil[/size][/font][/b][font=&quot;][size=9pt]) [/size][/font][b][font=&quot;][size=9pt]and[/size][/font][/b][font=&quot;][size=9pt]
            ((Instance.GetInterface(IUnknown, LUnknown) [/size][/font][b][font=&quot;][size=9pt]and[/size][/font][/b][font=&quot;][size=9pt] Supports(LUnknown, IID, Intf)) [/size][/font][b][font=&quot;][size=9pt]or[/size][/font][/b][font=&quot;][size=9pt] [/size][/font][font=&quot;][size=9pt]//<-- RefCount changed![/size][/font][font=&quot;][size=9pt]
             Instance.GetInterface(IID, Intf));
[/size][/font][b][font=&quot;][size=9pt]end[/size][/font][/b][font=&quot;][size=9pt];[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[font=&quot;][size=10pt]倒数第三行的地方,[/size][/font][font=&quot;][size=10pt]Supports 并不是直接通过 Instance[/size][/font][font=&quot;][size=10pt]去查询是否支持[/size][/font][font=&quot;][size=10pt]IHello[/size][/font][font=&quot;][size=10pt]接口的[/size][/font][font=&quot;][size=10pt],[/size][/font][font=&quot;][size=10pt]而是[/size][/font][font=&quot;][size=10pt]先去查询[/size][/font][font=&quot;][size=10pt]Instance 是否支持 IUnknown,然后通过IUnknown 去查询 IHello接口。[/size][/font][font=&quot;][size=10pt]我不清楚[/size][/font][font=&quot;][size=10pt] Delphi [/size][/font][font=&quot;][size=10pt]为什么这样处理。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]现在我们手动调试程序:[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]当执行[/size][/font][font=&quot;][size=10pt]Instance.GetInterface(IUnknown,LUnknown) [/size][/font][font=&quot;][size=10pt]之后,[/size][/font][font=&quot;][size=10pt]LUnknown [/size][/font][font=&quot;][size=10pt]指针指向了 [/size][/font][font=&quot;][size=10pt]Instance ([/size][/font][font=&quot;][size=10pt]即[/size][/font][font=&quot;][size=10pt] VI)[/size][/font][font=&quot;][size=10pt],同时因为接口引用计数的关系[/size][/font][font=&quot;][size=10pt]VI.FRefCount [/size][/font][font=&quot;][size=10pt]加一。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]然后程序继续执行[/size][/font][font=&quot;][size=10pt]Supports(LUnknown, IID, Intf)[/size][/font][font=&quot;][size=10pt]。这时[/size][/font][font=&quot;][size=10pt] Intf [/size][/font][font=&quot;][size=10pt]指针指向了[/size][/font][font=&quot;][size=10pt]IHello [/size][/font][font=&quot;][size=10pt]的真正实现者 [/size][/font][font=&quot;][size=10pt]VI.FImplementorOfHello[/size][/font][font=&quot;][size=10pt],同样的的,[/size][/font][font=&quot;][size=10pt]VI.FImplementorOfHello.FRefCount [/size][/font][font=&quot;][size=10pt]加一。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]当查询成功离开[/size][/font][font=&quot;][size=10pt]Supports [/size][/font][font=&quot;][size=10pt]函数时,本地变量指针 [/size][/font][font=&quot;][size=10pt]LUnknown [/size][/font][font=&quot;][size=10pt]会被清除,于是[/size][/font][font=&quot;][size=10pt] VI.FRefCount [/size][/font][font=&quot;][size=10pt]减一。不巧的是[/size][/font][font=&quot;][size=10pt] VI [/size][/font][font=&quot;][size=10pt]也是由 [/size][/font][font=&quot;][size=10pt]TInterfacedObject [/size][/font][font=&quot;][size=10pt]继承来的……。种种不幸最终酿成又一场惨祸。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[b][font=&quot;][size=10pt]最后总结[/size][/font][/b][b][font=&quot;][size=10pt][/size][/font][/b]
[font=&quot;][size=10pt]这篇文章除了要介绍一下接口的查询方法外,主要是要想交代一下我在具体使用接口中发现的一些问题。上述代码中包涵了[/size][/font][font=&quot;][size=10pt]3[/size][/font][font=&quot;][size=10pt]个问题:[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]1.[font=&quot;][size=7pt]     [/size][/font][/size][/font][font=&quot;][size=10pt]TInterfacedObject [/size][/font][font=&quot;][size=10pt]由于会在[/size][/font][font=&quot;][size=10pt] FRefCount=0 [/size][/font][font=&quot;][size=10pt]时释放掉对象实例,所以在使用上要格外小心。建议重新封装一个[/size][/font][font=&quot;][size=10pt]TInterfacedObjectEx[/size][/font][font=&quot;][size=10pt],或者改用 [/size][/font][font=&quot;][size=10pt]TComponent[/size][/font][font=&quot;][size=10pt]。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]2.[font=&quot;][size=7pt]     [/size][/font][/size][/font][font=&quot;][size=10pt]Supports [/size][/font][font=&quot;][size=10pt]内部这行代码虽不知其用意,但显然是不安全的!尤其是在使用委托机制实现接口封装的时候。[b][color=red]说明:我暂时无法证明去掉有问题的这行是否能保证不引入其它问题。[/color][/b][/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]3.[font=&quot;][size=7pt]     [/size][/font][/size][/font][font=&quot;][size=10pt]上述代码设计上的问题是:既然 [/size][/font][font=&quot;][size=10pt]TVirtualImplementor [/size][/font][font=&quot;][size=10pt]把接口的实现工作委托[/size][/font][font=&quot;][size=10pt] ([/size][/font][font=&quot;][size=10pt]外包[/size][/font][font=&quot;][size=10pt]) [/size][/font][font=&quot;][size=10pt]给了[/size][/font][font=&quot;][size=10pt] TRealImplementor[/size][/font][font=&quot;][size=10pt],那么[/size][/font][font=&quot;][size=10pt]TVirtualImplementor [/size][/font][font=&quot;][size=10pt]就应该定义成 [/size][/font][font=&quot;][size=10pt]TObject[/size][/font][font=&quot;][size=10pt]。尽管程序可以运行,但是逻辑上还是有些不通。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt]此外,委托[/size][/font][font=&quot;][size=10pt] (implements) [/size][/font][font=&quot;][size=10pt]这个概念挺有意思,它提高了接口的复用度。有时间的话,我会详细再写一篇介绍。[/size][/font][font=&quot;][size=10pt][/size][/font]
[font=&quot;][size=10pt] [/size][/font]
[size=10pt][/size]
[size=10pt] [/size]

[[i] 本帖最后由 stanleyxu2005 于 2007-8-3 23:44 编辑 [/i]]

2007-8-2 17:14 jAmEs_
implements这个有点意思好像,以前没有用过,希望讲讲~~

2007-8-2 22:13 zzzl
晕,本版块为最强技术含量的水园,鉴定完毕

2007-10-22 19:54 xwing
反正我不会同时混用接口和对象,问题多的很.实在要用,就让它不能自动引用计数.

页: [1]
查看完整版本: [原创] 查询接口小议


Powered by Discuz! Archiver 5.0.0  © 2001-2006 Comsenz Inc.