Процедуры и функции как параметры.
Существует класс задач, где исходными данными (аргументами) для программ (подпрограмм) являются не переменные и константы, а функции и процедуры. К таким задачам относятся например задача создания неких универсальных программ типа, например, универсальной программы построения графика нескольких функций, определенных на разных (своих) интервалах. Вид такой программы не должен зависеть от вида функции, используемой для вычисления значения на интервале.
Если бы такую универсальную программу построения графика делать без передачи функции как параметра, то необходимо было бы сделать две вещи: 1). Распознавать, для какой конкретно функции (интервала) надо строить график; 2). Для каждого конкретного вида функции надо было бы использовать свой специфический вызов этой функции для определения положения и вывода точки на графике.
Если в функцию построения графика передавать как параметр функцию, вычисляющую значение на интервале, то в общем виде заголовок этой функции (построения графика) можно было бы записать так:
функция f как формальный параметр
Procedure график(х : real; function f(x:real)) : real; (так писать нельзя)
Костяк универсальной процедуры построения графика может иметь следующий вид:
function f1 (...):real;
begin
...
end;
function f2 (...):real; Описания функций, для которых надо строить графики
begin
...
end;
function f3 (...):real;
begin
...
end; для построения графика функции f1(x) вызов
procedure график (x:real, function f(x: real)): real; процедуры имел бы вид: график(x, f1(x));
begin
В теле процедуры вывода графика используется один оператор вывода для всех функций (f1, f2, f3). |
writeln(.......... , f(x), ...);
end;
Конкретный вид функции указывался бы при вызове. В каждом конкретном случае вызывалась бы та функция, которая передавалась бы в качестве фактического параметра.
На Паскале в качестве формальных параметров допускается использовать имена процедур или функций. При вызове подпрограммы на место формальных параметров процедур или функций осуществляется подстановка имен соответствующих им фактических процедур или функций.
Но на Паскале нельзя описывать функцию как параметр в той форме, как это сделано выше (нельзя определять сложный тип прямо в заголовке). С этим мы уже сталкивались при передаче массивов как параметров.
Procedure f(a : array[1..10] of char);
неверно |
f: function (x: real);…) : real;
На Паскале для этого случая нужно объявить процедурный тип.
Имя функции не указывается |
func = function (x: real): real;
Справа от "=" фактически приводится заголовок функции, только без имени.
Процедурный тип определяет, какой вид подпрограммы (процедуру, функцию) можно использовать в качестве параметра и с какими параметрами должна вызываться эта подпрограмма. Фактически соответствующий формальный параметр будет являться параметром-значением, т. к. записывается без зарезервированного слова var.
Правильный заголовок процедуры построения графика в этом случае должен иметь следующий вид:
procedure plot (x: real; f: func);
begin
...
writeln (... , f(x), ...);
end;
Переменной процедурного типа f может быть присвоено в качестве значения имя функции, например f1 (соответствующего по типу и числу параметров вида). Выполнения функции f1 при таком присваивании не происходит, но при вызове вида f(x) вызываться будет f1.
Примеры объявлений:
Туре
Proc_0 = Procedure;{тип-процедура без параметров}
Ргос_2 = Procedure(Varх, у); {тип-процедура с 2-мя параметрами}
Ргос_3 = Procedure(a, b : real; Var у : real);{тип-процедура с 3-мя параметрами }
Func_0 = Function : integer;{тип-функция без параметров }
Func_1 = Function(s : real): real;{тип-функция с одним параметром }
Установлены следующие правила использования подпрограмм в качестве параметров:
§ правила совместимости: процедурные типы для совместимости по присваиванию должны иметь одинаковое число формальных параметров, а параметры на соответствующих позициях в заголовках, должны иметь эквивалентный тип. Кроме того, для функций должны совпадать типы возвращаемых значений;
§ согласно принципу опережающего описания объектов в Паскале, процедура или функция может обращаться только к той процедуре или функции, описание которых располагается перед описанием вызывающей процедуры или функции.
§ для установки правильных связей между вызывающими и вызываемыми подпрограммами вызываемые процедуры или функции (передаваемые как параметры) должны быть скомпилирована с использованием дальней модели вызовов с формированием их полного адреса, что достигается двумя путями: они должны компилироваться с директивой компилятору {SF+}
1-й путь
{$F+}
function f1(...): real;
Перед и после описания функции помещается директива {$F} |
...
end;
{$F-}
2-й путь:
function f1(...): real; far;
явно указана необходимость использования дальнего вызова в заголовке функции.
§ они не должны объявляться внутри других процедур или функций;
§ они не должны быть стандартными процедурами или функциями;
18.13 Директивы подпрограмм
Следующие директивы дают дополнительную информацию транслятору о размещении подпрограмм:
1. Директива FORWARD
Дата добавления: 2016-05-28; просмотров: 2031;