Насколько совместимы статические методы классов и обычные рутинные указатели?
Мне кажется, что методы статического класса и обычные указатели на рутину совместимы с практической точки зрения, но компилятор этого не знает. Пример:
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.
Как отмечено в комментариях, 3a и 3b оба компилируются (где компиляция включает работы во время выполнения в этом простом примере). 2a и 2b оба компилируются тогда и только тогда, когда $TYPEDADDRESS
является OFF
, Но 1a/1b отличаются: 1b всегда компилируется, а 1a никогда не компилируется. Это различие по дизайну? Используете ли вы 3a save или я пропустил какие-либо подводные камни?
1 ответ
На двоичном уровне нет никакой разницы между статической функцией класса и обычной функцией с одинаковыми аргументами и типом результата - они двоично совместимы, поэтому ваш пример в порядке. Конечно, это разные типы для компилятора, поэтому вам нужно Addr()
или же @
составить ваш пример.
Addr()
эквивалентно @
оператор, за исключением того, что он не зависит от директивы компилятора $T. Если вы переключите проверку типа в вашем примере, вы не скомпилируете:
{$T+}
begin
CallIt(@TMyClass.StaticMethod);
Readln;
end.
[Ошибка Паскаля] Project10.dpr(28): E2010 Несовместимые типы: 'TFunc' и 'Pointer'