Насколько совместимы статические методы классов и обычные рутинные указатели? - PullRequest
3 голосов
/ 04 августа 2011

Мне кажется, что методы статического класса и обычные указатели на рутину совместимы с практической точки зрения, но компилятор этого не знает.Пример:

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 Ответ

7 голосов
/ 04 августа 2011

На двоичном уровне нет никакой разницы между статической функцией класса и обычной функцией с одинаковыми аргументами и типом результата - они двоичные совместимы, поэтому ваш пример в порядке.Конечно, это разные типы для компилятора, поэтому вам нужно Addr() или @ для компиляции вашего примера.

Addr() эквивалентно оператору @, за исключением того, что на него не влияет $Директива компилятора T. Если вы переключите проверку типа, ваш пример не скомпилирует:

{$T+}
begin
  CallIt(@TMyClass.StaticMethod);
  Readln;
end.

[Pascal Error] Project10.dpr (28): E2010 Несовместимые типы: 'TFunc' и 'Pointer'

...