Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi.pdf
Скачиваний:
197
Добавлен:
24.02.2016
Размер:
6.84 Mб
Скачать

переданных данных. Заметим, что при вызове подпрограмм на место нетипизированных параметров (в том числе и на место нетипизированных const-параметров) можно подставлять только переменные.

Передача фактических аргументов в подпрограмму осуществляется через специальную область памяти — стек. В стек помещается либо значение передаваемого аргумента (передача значения), либо адрес аргумента (передача ссылки на значение). Конкретный способ передачи выбирается компилятором в зависимости от того, как объявлен параметр в заголовке подпрограммы. Связь между объявлением параметра и способом его передачи поясняет таблица 2.10:

Ключевое

Назначение

Способ передачи

слово

 

 

<отсутствует>

Входной

Передается копия значения

const

Входной

Передается копия значения либо ссылка на значение в

зависимости от типа данных

 

 

out

Выходной

Передается ссылка на значение

var

Входной и

Передается ссылка на значение

выходной

 

 

Таблица 2.10. Способы передачи параметров

Если передается значение, то подпрограмма манипулирует копией аргумента. Если передается ссылка на значение, то подпрограмма манипулирует непосредственно аргументом, обращаясь к нему через переданный адрес.

2.8.6. Опущенные параметры процедур и функций

В языке Delphi существует возможность задать параметрам процедур и функций стандартные значения. Они указываются через знак равенства после типа параметра. Например, опишем процедуру, которая заполняет некоторую область памяти заданным значением:

procedure Initialize(var X; MemSize: Integer; InitValue: Byte = 0);

Для параметра InitValue задано стандартное значение, поэтому его можно опустить при вызове процедуры Initialize:

Initialize(MyVar, 10); // Эквивалентно Initialize(MyVar, 10, 0);

Подпрограмма может содержать любое количество параметров со стандартными значениями, однако такие параметры должны быть

87

последними в списке. Другими словами, после параметра со стандартным значением не может следовать обычный параметр, поэтому следующее описание будет воспринято компилятором как ошибочное:

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

88

Если мы попробуем вызвать процедуру 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; // Правильно

89

Необходимо заметить, что при использовании перегруженных процедур (функций), у которых есть параметры, имеющие стандартные значения, нужно быть очень внимательным, т.к. могут возникнуть ситуации, когда компилятор просто не будет знать, какую именно процедуру (функцию) вы хотите вызвать. Например:

procedure Increment(var

Value: Real; Delta: Real = 1.0); overload; //

процедура 1

Value: Real); overload;

//

procedure

Increment(var

процедура

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; // Ошибка!

2.8.8. Соглашения о вызове подпрограмм

В различных языках программирования используются различные правила вызова подпрограмм. Для того чтобы из программ, написанных на языке Delphi, возможно было вызывать подпрограммы, написанные на других языках (и наоборот), в языке Delphi существуют директивы, соответствующие четырем известным соглашениям о вызове подпрограмм: register, stdcall, pascal, cdecl.

Директива, определяющая правила вызова, помещается в заголовок подпрограммы, например:

procedure Proc; register;

function Func(X: Integer): Boolean; stdcall;

Директива register задействует регистры процессора для передачи параметров и поэтому обеспечивает наиболее эффективный способ вызова подпрограмм. Эта директива применяется по умолчанию. Директива stdcall используется для вызова стандартных подпрограмм операционной системы.

90

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]