Р.У. Себеста - Основные копцепции языков программирования (2001) (1160794), страница 98
Текст из файла (страница 98)
Заметим также, что, поскольку адрес второго параметра вычисляется в начале выполнения функции 1цп, любое изменение глобальной переменной 1 не повлияет на ее адрес, используемый в конце при возвращении значения переменной 11вС [ 1]. 8.6. 88араметры, ввлвющиесв именами подпрограмм В программировании часто возникают ситуации, которые удобнее всего обрабатыззть. если имена подпрограмм передаются как параметры другим подпрограммам. В чат-ностга это происходит, когда подпрограмма должна моделировать некую математичет.зю функцию. Например, подпрограмма, выполняющая численное интегрирование. оптезеляет площадь фигуры, лежащей под графиком функции, вычисляя зту функцию в .слыхом количестве различных точек. Такая подпрограмма должна применяться для гюоой заданной функции.
Не должно возникать необходимости переписывать подпро-гачму лля каждой функции, которую следует проинтегрировать. Следовательно. естест!анно. чтобы имя функции в программе, вычисляющей интеграл математической функии. передавалось в подпрограмму интегрирования как параметр. Несмотря на то что эта идея вполне естественна и выглядит простой, детали ее рабо-л: чогут вызвать замешательство. Если бы требовалось передать только код подпро."аччы, то было бы достаточно передать отдельный указатель. Однако возникает не- колько осложняющих обстоятельств.
Во-первых, существует проблема проверки типов параметров при вызовах полпро.зччы, передаваемой как параметр. В исходном описании языка Рааса! ()епзеп ап6 'Л'лп, 1974) позволялось передавать подпрограммы как параметры без включения нн: орчации о типах нх параметров. Если возможна независимая компиляция (невозмож-зя в исходной версии языка Разса)), то компилятор не позволяет проверить лаже прая щьность количества параметров. В отсутствие независимой компиляции проверка совместимости параметров возможна, но представляет собой крайне сложную за.ачу и :оычно не выполняется.
Язык ГОКТКАХ 77 страдает от той же проблемы. но. поскольку зроверка совместимости типов в языке ГОКТКАХ 77 и так никогла не выполняется. она че является дополнительной проблемой. Если имя подпрограммы передается как параметр в языке АЕООЕ 68 илн в позлнейих версиях языка Рааса!, типы формальных параметров включаются в список формальных параметров, получаемых подпрограммой, так что совместимость типов параметров, тередаваемых в подпрограмму при реальном вызове, можно выполнить статически.
На.—.ример, рассмотрим следующий код на языке Разов!: ргооецпгв 1псейгасе(гипоцйоп Гоп(х: геа1]: геа1т 1онегЬ6, иррегЬ6 : геа1; маг гевц1г : геа1)т чаг биича1 ; геа1; Ьестдп бцпча1: = йип (1онегЬ6) епс1; Фактический параметр в вызове функции био в процедуре 1псе9гасе может быть статически проверен на совместимость с типом формального параметра функции 1ттп из списка формальных параметров процедуры 1пге9 гасе.
В языках С и С++ функции не могут передаваться как параметры, но указатели на фу нкции — могут. Типом указателя на функцию является ее протокол. Поскольку прото- 8.6. Параметры, являющиеся именами подпрограмм кол содержит типы всех параметров, такие параметры могут быть полностью проверены на совместимость типов.
В языке Мог)ц»а-2 типы процедур используются для их передачи, как если бы они были переменными. Этот метод позволяет выполнять проверку совместимости типов параметров передаваемых подпрограмм, поскольку типы параметров являются частью типа процедуры. В языке РОСТКА)4 90 есть механизм описания поллежащих проверке типов параметров подпрограмм, которые сами передаются как параметры. В языке Аг»а подпрограммы нельзя использовать в качестве параметров. Вместо этого функциональные возможности, обеспечиваемые передачей подпрограмм в качестве параметров.
в языке Ал(а достигаются с помощью настраиваемых функций, обсуждаемых в разделе 8.8. Более интересный аспект использования имен подпрограмм, передаваемых как параметры, связан с вопросом о правильной среде ссылок при выполнении передаваемой подпрограммы. Существуют три возможности. ). Среда оператора вызова, который активирует передаваемую подпрограмм) (теневое связывание — зйаПое Ь(пб(п8). 2. Среда определения передаваемой подпрограммы (глубокое связывание — деер Ь(ойп8). 3.
Среда оператора вызова, передающего подпрограмму как фактический параметр (специальное связывание — ад Ьос Ь(пб)п8). Следующий пример программы иллюстрирует эти возможности. Допустим, что проне- дура ЯВВЗ может вызывать процедуру 5054. ргосес(цге 50В1) чаг х : лпседегл ргосвс(цге ЯУВ24 Ъеслп нг(ге('х - ', х); впцл (лцЪ2) ргосеслцгв 50ВЗ; чаг х : лпгедегл Ьедлп х : лпседег; х := Зл Я()В4(БУВ2) епс)л (50ВЗ) ргосес)иге 5()В4 (Я()ВХ); чаг х : 1псе9егл Ьвс)лп х:= 4; ЯУВХл епс)л (ЯУВ4» Ьедлп (50В1) х:= 1; ЯУВЗ впс(; (ЯУВ1) Рассмотрим выполнение подпрограммы ЯВВ2 при ее вызове из 50В4. При теневом связывании среда ссылок такого выполнения совпадает со средой ссылок подпрограммы 50В4, так что ссылка на переменную х в подпрограмме ЯУВ2 связывается с локальной пе- ЗУ4 Глава 8.
Подпрограммы .= подпрограмме ЯЯВ4, и программа выводит строку х = 4. При глубоком :г. зз ссылок выполнения подпрограммы ЯВВ2 совпадает со средой ссылок - . ".= .. так что ссылка на переменную х в подпрограмме ЯБВ2 связывается ";.зсменной х в подпрограмме ЯУВ1, и программа выводит строку х = 1. - .:ч связывании ссылка на переменную х в подпрограмме ЯУВ2 связывается -:сеченной х в подпрограмме ЯЯВЗ, и программа выводит строку х = 3. .--., случаях подпрограмма, в которой объявляется другая подпрограмма, ° ...;- ее как параметр. В этих случаях глубокое связывание и специальное свя;зют между собой.
Специальное связывание никогда не использовалось, " можно предположить, среда, в которой процедура оказывается в качестве :, чеез естественной связи с передаваемой подпрограммой. .. = взывание неприемлемо для языков с блочной структурой из-за статическо-. з«ременных. Допустим, что процедура ЯЕИВЕВ передает процедуру ЯВИТ в процедуру йесе1чей. Проблема заключается в том, что процелура жет не принадлежать статической среде ссылок процедуры ЯВИТ, делая '; очень неестественным для процедуры ВЕЮТ доступ к переменным проце- С другой стороны, для любой процедуры в языках со статическим об- э, включая процедуры, передаваемые как параметры, вполне нормальной м.
° .. пия. когда среда ссылок определяется лексическим местонахождением ее ° с леэовательно. для языков с блочной структурой более логичным является е гл)бокого связывания. Некоторые языки с динамическим обзором дан.-:". = ' . используют теневое связывание 3 7. Перегруженные подпрограммы -: 'чый оператор имеет несколько значений.
Значение конкретного экземп+енного оператора определяется типами его операндов. Например, если ест зва операнда с плавающей точкой в программе на языке С, он означает .с. ~ с плавающей точкой. Однако, если тот же оператор имеет два целочис. - чза. он означает целочисленное умножение.
:-: - ° женная подпрограмма (отег!оадед зцЬргойгат) — это подпрограмма. нмя ззет с именем другой подпрограммы в той же среде ссылок. Каждая вер-.чной подпрограммы должна иметь свой уникальный протокол, т.е. она -ю ься от других версий количеством, порядком, типами своих параметров .ээзшаемого значения, если она является функцией.
Значение вызова пере—. -зрограммы определяется списком фактических параметров (и/или, воз: ь звращаемого значения при использовании функции). - узза и Ада солержат встроенные перегруженные подпрограммы. Наприлчеет несколько версий функции вывода РОТ. Наиболее широко испольгой функции. принимающие в качестве параметров строку, целое число и щеГ1 точкой. Поскольку каждая версия функции РУТ имеет уникальные :.— в.
компилятор может однозначно различать вызовы функции РОТ с раз- - ~ и параметров. -. ь=з тип возвращаемого значения в перегруженных функциях используется -..-.го определения вызываемой функции. Следовательно, две перегруженэг)т иметь одинаковый набор параметров и различаться только типом 37$ е = е — ь женныв подпрограммы возвращаемого значения. Это возможно, поскольку в языке Ада не позволяются смсшанныс выражения, так что контекст функции может определять тип возврашаемог; функцией значения.
В языках С++ и )ача смешанные выражения допускаются, поэтом, тип возвращаемого значения не играет никакой роли при однозначном определении перетру кенных функций (или методов). Пользователи также могут создавать несколько версий подпрограмм с одним и тем же именем на языках Аг(а, )ача и С++.
Несмотря на то что нет никакой необходимости в том, чтобы эти подпрограммы описывали в основном один и тот же процесс, они обычно делают именно это. Например, конкретная программа может нуждаться в двух процедурах сортировки, одной — лля целочисленных массивов и другой — для массивов чисел с плавающей точкой. Обе эти процедучы можно назвать ЯОКТ, поскольку типы их параметров различны.
В приведенной ниже скелетной программе на языке Ада содержатся две процедуры с именем ЯОАТ: ркооес(иле МА1И за су)ре ГЬОАТ НЕСТОР 1а аккау (1ИТЕОЕ(( капде <>) оГ ГЬОАТ; куре 1НТ НЕХТОА 1а аккау (1МТЕОЕА капде <>) ог 1ИТЕБЕКг ркоаес(иле ЯОАТ(ГЬОАТ Ь1ЯТ : хп оис ГЬОАТ НЕСТОР.; ЬОХЕК ВООИО : Еп 1ИТЕОЕР; ОРРЕ)( ВООИ : Еп 1ЫТЕСЕА) хв епс( БОРТ; ркооес(иле ЯОКТ(1(ЧТ Ь1ЯТ : йп оис 1(ЧТ НЕСТОГО ЬОХЕК БОСОГО : дп 1ИТЕОЕА; ОРРЕА ВОУХР : Еп 1ИТЕОЕй) ха епс( ЯОАТг епс1 ИА1Иг Перегруженные подпрограммы, имеющие параметры по умолчанию, могут привести к неоднозначным вызовам. В качестве примера рассмотрим следующий код на языке Сн: чойа Тип(Г1оак Ь = 0.0) чада Тип(); Гип (); Этот вызов является нео,нозначным и приведет к ошибке компиляции.