这是我的代码示例:
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;
答案 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;