如何从Delphi中的子类获取指向基类中方法的指针?

时间:2010-09-24 05:15:37

标签: delphi

这是我的代码示例:

type
  TMyBaseClass = class
  public
    procedure SomeProc; virtual;
  end;

  TMyChildClass = class(TMyBaseClass)
  public
    procedure SomeProc; override;
  end;

var
  SomeDelegate: procedure of object;

procedure TMyBaseClass.SomeProc;
begin
  ShowMessage('Base proc');
end;

procedure TMyChildClass.SomeProc;
begin
  ShowMessage('Child proc');
  // here i want to get a pointer to TMyBaseClass.SomeProc (NOT IN THIS CLASS!):
  SomeDelegate := SomeProc;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TMyChildClass.Create do
  try
    // there will be "Child proc" message:
    SomeProc;
  finally
    Free;
  end;
  // there i want to get "Base proc" message, but i get "Child proc" again
  // (but it is destroyed anyway, how coud it be?):
  SomeDelegate;
end;

2 个答案:

答案 0 :(得分:8)

我知道的一种方式是:

procedure TMyChildClass.BaseSomeProc;
begin
  inherited SomeProc;
end;


procedure TMyChildClass.SomeProc;
begin
  ShowMessage('Child proc');
  SomeDelegate := BaseSomeProc;
end;

第二个是将SomeProc声明从override更改为reintroduce

 TMyChildClass = class(TMyBaseClass)
 public
    procedure SomeProc; reintroduce;
 end;

然后将self转换为TMyBaseClass(不要使用as强制转换):

 SomeDelegate := TMyBaseClass(self).SomeProc;

另请注意,您的代码会提供访问冲突,因为您在已释放的对象上调用了SomeDelegate

答案 1 :(得分:4)

添加类型声明和一些类型转换工作,但附带一些警告说明。

正如您自己提到的那样,在释放实例后调用somedelegate并不是AV。这是因为您的SomeProc方法不使用任何实例变量,它只是调用ShowMessage。

如果您在调用中添加任何实例变量,如果尚未重新分配内存,您甚至可能仍然可以使用它。这将是一个等待发生的AV。

底线:

  • 不要在被破坏的对象上调用方法。
  • 在类的生命周期内设置一个全局变量并不是一个好的设计。
  • 在理想的设计中,除了通过调用继承之外,不应该让子类无论如何都要将调用还原为祖先的方法。

代码更改

...
type
  TSomeDelegate = procedure of object;

var
  SomeDelegate: TSomeDelegate;

...

procedure TMyChildClass.SomeProc;
var
  method: TMethod;
begin
  ShowMessage('Child proc');
  // here i want to get a pointer to TMyBaseClass.SomeProc (NOT IN THIS CLASS!):
  method.Code :=  @TMyBaseClass.SomeProc;
  method.Data := Self;
  SomeDelegate := TSomeDelegate(method);
end;