【问题标题】:Casting object to interface type with no TInterfacedObject as base class将对象转换为没有 TInterfacedObject 作为基类的接口类型
【发布时间】:2013-02-02 15:01:42
【问题描述】:

我需要一个没有引用计数的类实现接口。我做了以下事情:

  IMyInterface = interface(IInterface)
      ['{B84904DF-9E8A-46E0-98E4-498BF03C2819}'] 
      procedure InterfaceMethod;
  end;

  TMyClass = class(TObject, IMyInterface)
  protected
      function _AddRef: Integer;stdcall;
      function _Release: Integer;stdcall;
      function QueryInterface(const IID: TGUID; out Obj): HResult;stdcall;
  public
      procedure InterfaceMethod;
  end;

  procedure TMyClass.InterfaceMethod;
  begin
      ShowMessage('The Method');
  end;

  function TMyClass.QueryInterface(const IID: TGUID; out Obj): HResult;
  begin
      if GetInterface(IID, Obj) then
          Result := 0
      else
          Result := E_NOINTERFACE;
  end;

  function TMyClass._AddRef: Integer;
  begin
      Result := -1;
  end;

  function TMyClass._Release: Integer;
  begin
      Result := -1;
  end;

缺少引用计数可以正常工作。但我担心的是我不能使用as 运算符将TMyClass 转换为IMyInterface

var
  MyI: IMyInterface; 
begin
  MyI := TMyClass.Create as IMyInterface;

给我

[DCC 错误] E2015 运算符不适用于此操作数类型

TMyClass 派生自TInterfacedObject 时,问题就消失了——也就是说,我可以在没有编译器错误的情况下进行这种转换。显然我不想使用 TInterfacedObject 作为基类,因为它会使我的类引用计数。为什么不允许这种强制转换以及如何解决它?

【问题讨论】:

  • 在接口声明中添加 GUID 可能会获得更好的结果。在= interface 行之后添加一个新行,然后按 Ctrl-Shft-G。 asGetInterfacesupports等需要能够通过GUID识别接口才能工作。
  • 你没有仔细阅读我的帖子。当我从 TInterfacedObject 派生时,它可以工作。 GUID 与这里无关。您只需要 GUID 即可使用 COM。
  • 嗯,哪个 Delphi 版本?
  • 不,您不仅需要 GUID 来使用 COM。您需要 GUID 才能在许多方面使用接口。您是否尝试过添加 GUID 并查看会发生什么?
  • @DavidHeffernan 在将 IInterface 添加到它的工作列表后。您能否发布一个答案,以便我可以通过一些解释接受它?

标签: delphi interface delphi-xe2


【解决方案1】:

您不能在代码中使用as 的原因是您的类没有在其支持的接口列表中明确列出IInterface。即使您的接口派生自 IInterface,除非您实际列出该接口,否则您的类不支持它。

因此,简单的解决方法是像这样声明您的类:

TMyClass = class(TObject, IInterface, IMyInterface)

您的类需要实现IInterface 的原因是编译器依赖它来实现as 转换。

我想说的另一点是,一般来说,您应该避免使用接口继承。总的来说,它没有什么用处。使用接口的好处之一是您可以摆脱实现继承带来的单一继承约束。

但无论如何,所有 Delphi 接口 automatically inherit from IInterface 所以在你的情况下没有必要指定。我会这样声明你的界面:

IMyInterface = interface
  ['{B84904DF-9E8A-46E0-98E4-498BF03C2819}'] 
  procedure InterfaceMethod;
end;

更广泛地说,您应该尽量不要在接口中使用继承。通过采用这种方法,您将鼓励减少耦合并带来更大的灵活性。

【讨论】:

  • 接口继承不是实现继承。 Delphi 中的任何接口都派生自IInterface。最后一句不清楚。
  • @Serg 接口继承不是 实现继承正是我想要说明的重点。我会尝试清理它。
  • 还值得一提的是,使用接口继承减少了实例大小。无论您使用TMyClass = class(TObject, IMyInterface) 还是TMyClass = class(TObject, IInterface, IMyInterface),在Delphi XE 中实例大小都是12 字节,因为IMyInterface 继承自IInterfaceIInterface 支持的显式声明仅在编译时很重要,并且不会使代码膨胀一点。
  • @David,您很可能想写“...避免使用接口继承”而不是“...避免使用实现继承”。我认为“错字”让 Serg 感到困惑
  • @iamjoosy 是的,就是这样。谢谢你。现在修好了。我也不喜欢实现继承,但那是另一回事!
猜你喜欢
  • 2011-07-23
  • 1970-01-01
  • 2013-01-08
  • 1970-01-01
  • 1970-01-01
  • 2017-05-24
  • 1970-01-01
  • 2018-06-20
  • 1970-01-01
相关资源
最近更新 更多