3.6 Процедурный тип |
Вверх Предыдущий Следующий |
Free Pascal имеет поддержку процедурных типов, она мало чем отличается от ее реализации в Turbo Pascal или Delphi. Объявление типа остается тем же самым, как может быть замечено по следующей синтаксической схеме: Процедурный тип Для описания списков формальных параметров см. главу Глава 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, оператор адреса(@) может быть опущен.
Поскольку тип 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 (делегация). |