问题
It seems to me that static class methods and regular routine pointers are compatible from a practical viewpoint but the compiler doesn't know this. Example:
type
TFunc = function(i: Integer): string;
TMyClass = class
public
class function StaticMethod(i: Integer): string; static;
end;
class function TMyClass.StaticMethod(i: Integer): string;
begin
Result := '>' + IntToStr(i) + '<';
end;
function GlobalFunc(i: Integer): string;
begin
Result := '{' + IntToStr(i) + '}';
end;
procedure CallIt(func: TFunc);
begin
Writeln(func(42));
end;
begin
CallIt(TMyClass.StaticMethod); // 1a: doesn't compile
CallIt(GlobalFunc); // 1b: compiles
CallIt(@TMyClass.StaticMethod); // 2a: compiles iff $TYPEDADDRESS OFF
CallIt(@GlobalFunc); // 2b: compiles iff $TYPEDADDRESS OFF
CallIt(Addr(TMyClass.StaticMethod)); // 3a: compiles
CallIt(Addr(GlobalFunc)); // 3b: compiles
Readln;
end.
As noted in the comments, 3a and 3b both compile (where compiles includes works at runtime in this simple example). 2a and 2b both compile if and only if $TYPEDADDRESS
is OFF
. But 1a/1b are different: 1b always compiles while 1a never compiles. Is this distinction by design? Is using 3a save or have I overlooked any pitfalls?
回答1:
There is no difference on binary level between static class function and ordinary function with the same arguments&result type - they are binary compatible, so your example is OK. Of course they are different types for the compiler, so you need Addr()
or @
to compile your example.
Addr()
is equivalent to the @
operator except that it is unaffected by the $T compiler directive.If you switch type check on your example will not compile:
{$T+}
begin
CallIt(@TMyClass.StaticMethod);
Readln;
end.
[Pascal Error] Project10.dpr(28): E2010 Incompatible types: 'TFunc' and 'Pointer'
来源:https://stackoverflow.com/questions/6940171/how-compatible-are-static-class-methods-and-regular-routine-pointers