【问题标题】:How do you override delegated method implementation?你如何覆盖委托的方法实现?
【发布时间】:2012-03-02 03:34:59
【问题描述】:

在 Delphi 2007 中,我使用一个类来实现第二类支持的接口之一。这是有效的。 Delphi 帮助指出:

默认情况下,使用 implements 关键字代表所有接口 方法。但是,您可以使用方法解析子句或声明 类中实现某些接口方法的方法 覆盖此默认行为。

但是,当我在我的第二个类中声明一个具有与其中一个接口方法匹配的签名的方法时,它不会被调用。

我想知道这是不是因为我在创建该类时通过另一个接口访问它。

下面是一个演示我的问题的测试程序:

program Project1;

{$APPTYPE CONSOLE}

type
  IInterface1 = interface
  ['{15400E71-A39B-4503-BE58-B6D19409CF90}']
    procedure AProc;
  end;

  IInterface2 = interface
  ['{1E41CDBF-3C80-4E3E-8F27-CB18718E8FA3}']
  end;

  TDelegate = class(TObject)
  protected
    procedure AProc;
  end;

  TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
  strict private
    FDelegate: TDelegate;
    property Delegate: TDelegate read FDelegate implements IInterface1;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AProc;
  end;

procedure TDelegate.AProc;

begin
  writeln('TClassDelegate.AProc');
end;

constructor TMyClass.Create;
begin
  inherited;
  FDelegate := TDelegate.Create;
end;

destructor TMyClass.Destroy;
begin
  FDelegate.Free;
  inherited;
end;

procedure TMyClass.AProc;

begin
  writeln('TMyClass.AProc');
end;

var
  MyObj : IInterface2;

begin
    MyObj := TMyClass.Create;
   (MyObj as IInterface1).AProc;
end.

当我运行它时,我得到了输出:

TClassDelegate.AProc

我想要的是:

TMyClass.AProc

任何帮助表示赞赏。

【问题讨论】:

  • 注释掉“FDelegate := TDelegate.Create;”并运行它,你会玩得很开心(:
  • @DorinDuminica,感谢您的建议。这并没有改变行为。同样在我的真实代码中,TDelegate中还有其他的属性和方法,所以我想我需要构造一个实例来避免访问冲突。干杯。
  • 我知道,我觉得奇怪的是代码在没有创建实例的情况下工作,这是我唯一的观点,抱歉没用):
  • 您正在调用IInterface1.AProcmyObj as IInterface1 = TDelegate 实例)所以(myObj as IInterface1).AProc 等于FDelegate.AProc。所以这种行为是预期的并且是正确的。如果你想调用TMyClass.AProc,你应该使用TMyClass 引用来调用它。如果你没有类引用,你想要TMyClass的调用过程?
  • 好的 :) 我明白你的意思了 :) 请参阅下面的答案。

标签: delphi delphi-2007


【解决方案1】:

看来你必须以这种方式重新声明你的方法:

TMyClass = class(TInterfacedObject, IInterface1, IInterface2)
strict private
  ....
  procedure test();
public
  ....
  procedure  IInterface1.AProc = test;
end;

procedure TMyClass.test;
begin
  writeln('TMyClass.AProc');
end;

所以IInterface1.AProc for TMyClass 映射到Test()(而不是FDelegate.AProc) 结果是TMyClass.AProc

【讨论】:

  • 感谢 teran,这对我有用。请注意,如果 test() 是严格私有的,则它不会编译,我必须对其进行保护。
  • 可能是 :) 在 d2010 中编译正常
  • 它猜它适合我仍然使用 D2007。我只是害怕移植这个项目。总有一天我应该咬紧牙关。
【解决方案2】:

documentation 明确指出您看到的行为是设计好的:

如果委托属性是类类型,则在搜索该类及其祖先之前搜索实现指定接口的方法,然后搜索封闭类及其祖先。

我猜在完整示例中,您有一个包含多个方法的接口,并且想要委托指定的大多数方法,以及由实现类覆盖的特定方法。我看不出如何只用一个类来实现这一点,但如果你引入第二个类就可以做到:

program Project1;

{$APPTYPE CONSOLE}

type
  IInterface1 = interface
  ['{15400E71-A39B-4503-BE58-B6D19409CF90}']
    procedure AProc;
    procedure AnotherProc;
  end;

  TDelegate = class
  protected
    procedure AProc;
    procedure AnotherProc;
  end;

  TMyClass = class(TInterfacedObject, IInterface1)
  strict private
    FDelegate: TDelegate;
    property Delegate: TDelegate read FDelegate implements IInterface1;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AProc;
  end;

  TMyOtherClass = class(TMyClass, IInterface1)
    procedure IInterface1.AProc = AProc;
  end;

procedure TDelegate.AProc;
begin
  writeln('TDelegate.AProc');
end;

procedure TDelegate.AnotherProc;
begin
  writeln('TDelegate.AnotherProc');
end;

constructor TMyClass.Create;
begin
  inherited;
  FDelegate := TDelegate.Create;
end;

destructor TMyClass.Destroy;
begin
  FDelegate.Free;
  inherited;
end;

procedure TMyClass.AProc;
begin
  writeln('TMyClass.AProc');
end;

var
  MyObj: IInterface1;

begin
  MyObj := TMyOtherClass.Create;
  MyObj.AProc;
  MyObj.AnotherProc;
  Readln;
end.

正如@teran 指出的那样,如果您准备重命名您的方法,那么有一个更简单的解决方案。

【讨论】:

  • 谢谢大卫,我在文档中读过那一点,然后在我的挣扎中又失去了它。我认为在封闭类中为方法使用不同的名称没有问题,所以我将使用@teran 的解决方案。
【解决方案3】:

这可能是由于属性的可见性。每次我使用implements 时,属性都是protectedpublic,对于我可以在VCL 中找到的所有示例(例如TAutoObjectEvent

尝试 #2:

如果从TMyClass 中删除AProc() 方法会发生什么?然后它会使用TDelegate 上的那个吗?

【讨论】:

  • 我尝试将 TMyClass.Delegate 更改为 public,但没有任何区别。同样,将 TDelegate.AProc 更改为 public 没有任何区别。感谢您的建议。
  • 尝试 #2:是的。这一切都按预期工作,我的问题是试图覆盖委托的实现。
【解决方案4】:

您提到的文档部分似乎已过时。如果您尝试对implements 子句中使用的接口使用方法解析,您将收到编译器错误E2264: Cannot have method resolutions for interface '%s'

上面链接中显示的解决方案 - 简单地将过程与接口中声明的名称相同 - 在 Delphi XE 中似乎也不起作用(它编译但不调用过程)。

【讨论】:

  • 谢谢。奇怪的是,除非我误读,否则该链接中的解决方案与我正在尝试但不起作用的方法相同。感谢您确认它在 XE 中也不起作用。我想知道这是否是 D2007 的特性。如果我有时间移植到 XE,至少我不必追逐这个弱点。 @teran 的带有方法解析子句的解决方案可以编译并运行。
猜你喜欢
  • 1970-01-01
  • 2011-09-28
  • 2012-02-13
  • 2010-11-18
  • 2014-12-13
  • 2012-04-02
  • 2019-08-17
  • 2014-08-18
  • 2019-07-29
相关资源
最近更新 更多