
- •2.1.3. Слова-идентификаторы
- •2.1.4. Комментарии
- •2.2.2. Константы
- •2.2.3. Переменные
- •2.3.2. Вещественные типы данных
- •2.3.3. Символьные типы данных
- •2.3.4. Булевские типы данных
- •2.3.5. Определение новых типов данных
- •2.3.6. Перечисляемые типы данных
- •2.3.7. Интервальные типы данных
- •2.3.8. Временной тип данных
- •2.3.9. Типы данных со словом type
- •2.4.2. Арифметические операции
- •2.4.3. Операции отношения
- •2.4.4. Булевские операции
- •2.4.5. Операции с битами
- •2.4.6. Очередность выполнения операций
- •2.5.2. Консольный вывод
- •2.6.1. Заголовок программы
- •2.6.2. Подключение модулей
- •2.6.3. Программный блок
- •2.7.2. Оператор присваивания
- •2.7.3. Оператор вызова процедуры
- •2.7.4. Составной оператор
- •2.7.5. Оператор ветвления if
- •2.7.6. Оператор ветвления case
- •2.7.7. Операторы повтора - циклы
- •2.7.8. Оператор повтора for
- •2.7.9. Оператор повтора repeat
- •2.7.11. Прямая передача управления в операторах повтора
- •2.7.12. Оператор безусловного перехода
- •2.8.2. Стандартные подпрограммы Арифметические функции
- •2.8.3. Процедуры программиста
- •2.8.4. Функции программиста
- •2.8.5. Параметры процедур и функций
- •2.8.6. Опущенные параметры процедур и функций
- •2.8.7. Перегрузка процедур и функций
- •2.8.8. Соглашения о вызове подпрограмм
- •2.8.9. Рекурсивные подпрограммы
- •2.8.10. Упреждающее объявление процедур и функций
- •2.8.11. Процедурные типы данных
- •2.9.2. Стандартные модули языка Delphi
- •2.9.3. Область действия идентификаторов
- •Глава 3. Объектно-ориентированное программирование (ооп). Часть I
- •Глава 6. Интерфейсы
- •Глава 7. Проект приложения.
- •Глава 8. Меню, строка состояния и панель инструментов. Часть I
- •Глава 8. Меню, строка состояния и панель инструментов. Часть II
- •Глава 8. Меню, строка состояния и панель инструментов. Часть II
- •Глава 8. Меню, строка состояния и панель инструментов. Часть IV
- •Глава 9. Окна диалога. Часть I
- •Глава 9. Окна диалога. Часть II
- •Глава 9. Окна диалога. Часть III
2.8.6. Опущенные параметры процедур и функций
В языке Delphi существует возможность задать параметрам процедур и функций стандартные значения. Они указываются через знак равенства после типа параметра. Например, опишем процедуру, которая заполняет некоторую область памяти заданным значением:
procedure Initialize(var X; MemSize: Integer; InitValue: Byte = 0);
Для параметра InitValue задано стандартное значение, поэтому его можно опустить при вызове процедуры Initialize:
Initialize(MyVar, 10); // Эквивалентно Initialize(MyVar, 10, 0);
Подпрограмма может содержать любое количество параметров со стандартными значениями, однако такие параметры должны быть последними в списке. Другими словами, после параметра со стандартным значением не может следовать обычный параметр, поэтому следующее описание будет воспринято компилятором как ошибочное:
procedure Initialize(var X; InitValue: Byte = 0; MemSize: Integer); // Ошибка!
2.8.7. Перегрузка процедур и функций
В некоторых случаях возникает необходимость в написании подпрограмм, которые выполняют одинаковые логические действия, но над переменными разных типов данных. Например:
procedure IncrementInteger(var Value: Integer);
procedure IncrementReal(var Value: Real);
В языке Delphi существует возможность дать двум и более процедурам (функциям) одинаковые идентификаторы при условии, что все такие процедуры (функции) отличаются списком параметров. Такая возможность называется перегрузкой. Для указания того, что процедура (функция) перегружена, служит стандартная директива overload. С ее помощью вышеприведенный пример можно переписать следующим образом:
procedure Increment(var Value: Integer); overload; // процедура 1
procedure Increment(var Value: Real); overload; // процедура 2
Какую именно процедуру использовать в том или ином случае компилятор будет определять на этапе компиляции программы по типам фактических аргументов, передаваемых при вызове.
var
X: Integer;
Y: Real;
begin
X:=1;
Y:=2.0;
Increment(X); // Вызывается процедура 1
Increment(Y); // Вызывается процедура 2
end.
При перегрузке процедур и функций существует особенность, связанная с целочисленными типами данных. Допустим, имеются две процедуры:
procedure Print(X: Shortint); overload; // процедура 1
procedure Print(X: Longint); overload; // процедура 2
Если мы попробуем вызвать процедуру Print, указав в качестве фактического аргумента целочисленную константу, то увидим, что выбор компилятором варианта процедуры зависит от значения константы.
Print(5); // Вызывается процедура 1
Print(150); // Вызывается процедура 2
Print(-500); // Вызывается процедура 2
Print(-1); // Вызывается процедура 1
Очевидно, что одно и то же число может интерпретироваться и как Longint, и как Shortint (например, числа 5 и -1). Логика компилятора в таких случаях такова: если значение фактического параметра попадает в диапазон значений нескольких типов, по которым происходит перегрузка, то компилятор выбирает процеудуру (функцию), у которой тип параметра имеет меньший диапазон значений. Например, вызов Print(5) будет означать вызов того варианта процедуры, который имеет тип параметра Shortint. А вот вызов Print(150) будет означать вызов того варианта процедуры, который имеет тип параметра Longint, т.к. число 150 не вмещается в диапазон значений типа данных Shortint.
Поскольку в нынешней версии среды Delphi обощенный тип данных Integer совпадает с фундаментальным типом данных Longint, следующий вариант перегрузки является ошибочным:
procedure Print(X: Integer); overload;
procedure Print(X: Longint); overload; // Ошибка!
Такая же ошибка возникает при использовании пользовательских типов данных, определенных через общий базовый тип.
type
TMyInteger = Integer;
procedure Print(X: Integer); overload;
procedure Print(X: TMyInteger); overload; // Ошибка!
Что делать в тех случаях, когда такая перегрузка просто необходима? Для этого пользовательский тип данных необходимо создавать с использованием ключевого слова type:
type
TMyInteger = type Integer;
procedure Print(X: Integer); overload;
procedure Print(X: TMyInteger); overload; // Правильно
Необходимо заметить, что при использовании перегруженных процедур (функций), у которых есть параметры, имеющие стандартные значения, нужно быть очень внимательным, т.к. могут возникнуть ситуации, когда компилятор просто не будет знать, какую именно процедуру (функцию) вы хотите вызвать. Например:
procedure Increment(var Value: Real; Delta: Real = 1.0); overload; // процедура 1
procedure Increment(var Value: Real); overload; // процедура 2
Вызов процедуры Increment с одним параметром вызовет неоднозначность:
var
X: Real;
begin
Increment(X, 10); // Вызывается процедура 1
Increment(X); // Ошибка! Неоднозначность
end.
Запрещается также перегружать функции, которые отличаются лишь типом возвращаемого значения.
function SquareRoot(X: Integer): Single; overload;
function SquareRoot(X: Integer): Double; overload; // Ошибка!