Перегрузка имен подпрограмм
В одном пространстве имен может быть определено несколько процедур или функций с одним именем, но разным количеством или типами параметров. Имена таких процедур и функций называются перегруженными, а их создание - перегрузкой имен. Разновидностью перегрузки имен является перегрузка операций.
При вызове перегруженной процедуры или функции выбирается та версия, у которой типы формальных параметров совпадают с типами фактических или наиболее близки к ним. Например, если имеются описания
procedure p(b: byte); begin
end;
procedure p(r: real);
begin
end;
то при вызове p(1.0)
будет выбрана перегруженная
версия с параметром типа real
(точное
соответствие), а при вызове p(1)
будет
выбрана перегруженная версия с параметром типа byte
(при
этом произойдет преобразование фактического параметра типа integer
к типу byte
).
Заметим, что, в отличие от Object Pascal, использовать при
перегрузке служебное слово overload
не нужно.
Если ни одна версия в текущем пространстве имен не подходит к данному вызову, то возникает ошибка компиляции. Если две и более версии одинаково хорошо подходят к данному вызову, то также возникает ошибка компиляции, заключающаяся в неоднозначности выбора подпрограммы. Например, если имеются описания
procedure p(i: integer; r: real);
begin
end;
procedure p(r: real; i: integer);
begin
end;
то при вызове p(1,2)
оба
они одинаково подходят, что приводит к неоднозначности.
Запрещено перегружать подпрограмму другой подпрограммой с тем же количеством и типами параметров, отличающихся лишь тем, передается ли параметр по значению или по ссылке. Например, описания
procedure p(i: integer);
и
procedure p(var i: integer);
считаются одинаковыми.
Возвращаемое значение функции не участвует в разрешении перегрузки, т.е. перегружаемые функции не могут различаться только типами возвращаемых значений.
Алгоритм перегрузки имен при наличии нескольких подключенных модулей, а также алгоритм перегрузки имен методов имеют особенности. Основная особенность этих алгоритмов состоит в том, что они работают через границы пространств имен.
Поиск перегруженного
имени глобальной подпрограммы при наличии нескольких
подключенных модулей происходит во всех
модулях. При этом вначале осуществляется просмотр текущего модуля, а потом всех
модулей, подключенных в секции uses
,
в порядке справа налево. Если при этом поиске находится объект, который
не может перегружать предыдущие (например, перегружается процедура, а найдено
имя переменной), то цепочка перегрузки заканчивается, и поиск наилучшей
перегруженной подпрограммы идет среди найденных до этого момента. Если в модуле,
откомпилированном позже, имеется подпрограмма с точно такими же параметрами, то
она скрывает версию из модуля, откомпилированного раньше.
Например, пусть основная программа подключает два модуля -
un1
и un2
:
main.pas
uses un2,un1;
procedure p(i: integer);
begin
write(1);
end;
begin
p(2.2);
p(2);
end.
un2.pas
unit un2;
procedure p(r: real);
begin
write(3);
end;
end.
un1.pas
unit un1;
procedure p(r: real);
begin
write(2);
end;
end.
В результате будет выведено 21
,
что означает, что первой была вызвана процедура p
из модуля un1
.
Поиск перегруженного имени метода осуществляется аналогично:
вначале осуществляется просмотр текущего класса, затем его базового класса и
т.д. до класса Object
, либо до того момента, как будет встречен
объект, который не может перегружать предыдущие (имя поля или
свойства). Из всех найденных таким образом одноименных методов выбирается
наилучший. При этом в
разных классах могут быть методы с идентичными параметрами;
в этом случае вызывается первый встреченный метод от данного
класса к классу Object
.
Подпрограммы с переменным числом параметров также участвуют в перегрузке, однако, обычные подпрограммы имеют над ними приоритет. Например, в ситуации
procedure p(i: integer);
begin
write(1);
end;
procedure p(params a: array of integer);
begin
write(2);
end;
begin
p(1)
end.
будет вызвана первая процедура.