Reputation: 365
Here is my code example:
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;
Upvotes: 3
Views: 1232
Reputation: 58431
Adding a type declaration and some typecasting works but comes with some notes of warning.
As you've mentioned it yourself, the call to somedelegate after the instance has been freed doesn't AV. This is because your SomeProc method doesn't use any instance variables, all it does is calling ShowMessage.
Should you add any instance variables to the call, you even might still get away with it if the memory has not been reassigned. It would be an AV waiting to happen.
Bottom line:
Code changes
...
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;
Upvotes: 4
Reputation: 54292
The one way I know is:
procedure TMyChildClass.BaseSomeProc;
begin
inherited SomeProc;
end;
procedure TMyChildClass.SomeProc;
begin
ShowMessage('Child proc');
SomeDelegate := BaseSomeProc;
end;
The 2nd is to change SomeProc
declaration from override
to reintroduce
:
TMyChildClass = class(TMyBaseClass)
public
procedure SomeProc; reintroduce;
end;
and then cast self
as TMyBaseClass
(do not use as
cast):
SomeDelegate := TMyBaseClass(self).SomeProc;
Also note that your code will give Access Violation because you call SomeDelegate
on already freed object.
Upvotes: 8