3.6 Процедурный тип

На верх  Назад  Вперёд

Free Pascal имеет поддержку процедурных типов, она мало чем отличается от ее реализации в Turbo Pascal или Delphi. Объявление типа остается тем же самым, как может быть замечено по следующей синтаксической схеме:


Процедурный тип

313


Для описания списков формальных параметров см. главу Глава 14 Использование функций и процедур. Два следующих примера - допустимые описания типа:

Type

TOneArg = Procedure (Var X : integer);

TNoArg = Function : Real;

var

  proc : TOneArg;

  func : TNoArg;

Можно присвоить следующие значения переменной процедурного типа:

1.Nil, как для указателей обычной процедуры так и указателей метода.

2.Ссылку на переменную процедурного типа, то есть другой переменной того же типа.

3.Глобальный адрес процедуры или функции, с соответствующим заголовком и соглашением о вызове функции или процедуры.

4.Адрес метода.

Учитывая эти объявления, следующие присвоения допустимы:

Procedure printit (Var X : Integer);

begin

WriteLn (x);

end;

...

Proc := @printit;

Func := @Pi;

Из этого примера, ясна разница с Turbo Pascal: в Turbo Pascal нет необходимости использовать оператор адреса (@) при присвоении значения переменной процедурного типа, тогда как в Free Pascal это необходимо. В случае использования директив-переключателей -MDelphi или -MTP, оператор адреса(@) может быть опущен.

Замечание:

модификаторы, касающиеся соглашения о вызове, должны быть такими же как и в объявлении процедурного типа; то есть следующий код вызвал бы ошибку:

Type TOneArgCcall = Procedure (Var X : integer);cdecl;

var proc : TOneArgCcall;

Procedure printit (Var X : Integer);

begin

  WriteLn (x);

end;

begin

Proc := @printit;

end.

Поскольку тип TOneArgCcall это процедура, которая использует соглашение о вызове Cdecl.

В случае если, добавляется модификатор is nested (вложен), то процедурная переменная может использоваться вложенными процедурами. Это требует, чтобы код компилировался в режиме MACPAS или ISO, или что был активирован переключатель режима {$modeswitch nestedprocvars} :

{$modeswitch nestedprocvars}

program tmaclocalprocparam3;

 

type

tnestedprocvar = procedure is nested;

 

var

tempp: tnestedprocvar;

 

procedure p1( pp: tnestedprocvar);

begin

tempp:=pp;

tempp

end;

 

procedure p2( pp: tnestedprocvar);

var

localpp: tnestedprocvar;

begin

localpp:=pp;

p1( localpp)

end;

 

procedure n;

begin

writeln( 'Вызов через n');

end;

 

procedure q;

var qi: longint;

 

procedure r;

begin

  if qi = 1 then

    writeln( 'Успех для r')

  else

    begin

    writeln( 'сбой');

    halt( 1)

  end

end;

 

begin

qi:= 1;

p1( @r);

p2( @r);

p1( @n);

p2( @n);

end;

 

begin

q;

end.

В случае, если кто-то хочет назначить метод класса переменной процедурного типа, процедурный тип должен быть объявлен с модификатором of object.

В следующем примере представлены допустимые объявления двух процедурных переменных для метода (также известные как обработчиков событий, потому что их использования в дизайне GUI ):

Type

  TOneArg = Procedure(Var X : integer) of object;

  TNoArg = Function : Real of object;

var

oproc : TOneArg;

ofunc : TNoArg;

Объявление этих функций показывают как это правильно сделать. При их вызове, Self будет указывать на экземпляр объекта, который был использован для объявления процедуры метода.

Следующие методы объекта могут быть присвоены переменным oproc и ofunc:

Type

TMyObject = Class(TObject)

  Procedure DoX (Var X : integer);

  Function DoY: Real;

end;

 

Var

M : TMyObject;

 

begin

oproc:=@M.DoX;

ofunc:=@M.DOY;

end;

При вызове oproc и ofunc, Self будет равна M.

Этот механизм иногда называют Delegation (делегация).