Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Модули в Pascal и Delphi лекция.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
216 Кб
Скачать
☆

3 Подпрограммы в модулях

Процедуры и функции могут использоваться в модулях на­равне с другими Pascal-объектами. Однако для них имеются особенности, обусловленные их структурой. Заголовок подпрограммы содержит всю ин­формацию, необходимую для ее вызова: ее имя, количество и типы параметров и (для функций) тип результата. С другой стороны, описание подпрограммы содержит блок, раскрывающий ее алгоритм. Можно считать, что заголовок подпрограммы является ее интерфейсом, а описание и операторы – ее реализацией. Поэтому логично в интерфейсной части модуля представить только ЗАГОЛОВКИ процедур и функций, они будут видимы (доступны) для других программ, а их полные описания будут содержаться в разделе реализации. При этом полное описание подпрограммы мо­жет иметь СОКРАЩЕННЫЙ заголовок, состоящий только из служебного слова procedure или function, имени подпро­граммы и символа ';'. (Можно повторить полный заголовок подпрограммы, но тогда он должен быть совпадать с заголовком в интерфейсной части).

В качестве примера можно привести модуль, содержа­щий средства работы с комплексными числами:

unit CmplVals;

interface

type

Complex = record { способ представления комплексных чисел }

Re, Im : real

end;

{ Заголовки процедур, реализующих операции над комплексными числами }

procedure InitC (С:Complex;R,I:real);

procedure AddC (CI,C2:Complex;var R:Complex);

procedure MultC (CI,C2:Complex;var R:Complex);

procedure DivC (CI,C2:Complex;var R:Complex);

procedure WriteC(C:Complex);

implementation

{ Полные описания процедур (с сокращенными заголовками) }

procedure InitC;

begin

with С do

begin

Re:=R; Im:=I

end

end;

procedure AddC;

begin

with R do

begin

Re := Cl.Re+C2.Re; Im := Cl.Im+C2.Im

end

end;

procedure MultС;

begin

with R do

begin

Re := Cl.Re*C2.Re+Cl.Im+C2.Im; Im := Cl.Im*C2.Re+Cl.Re*C2.Im

end

end;

procedure DivC;

var

Tmp : real;

begin

with C2 do

Tmp:=Re*Re+Im*Im;

with R do

begin

Re := (Cl.Re*C2.Re+Cl.Im*C2.Im)/Tmp; Im := (C2.Re*Cl.Im+Cl.Re*C2.Im)/Tmp

end

end;

procedure WriteC;

begin

with С do

begin

Write(Re);

if lm=0 then

Exit;

if lm>0 then

Write('+');

Write(Im); Write('i')

end

end;

end.

Таким образом, механизм модулей позволяет скрыть детали реализации тех или иных программных подсистем, предоставив в распоряжение использующих их программ стро­го определенную совокупность интерфейсных объектов. Ес­ли необходимо, например, расширить модуль CmplVals вве­дением новых процедур или изменить реализацию какой-ли­бо процедуры, то если интерфейс модуля при этом останется неизменным, такая модификация НИКАК НЕ ОТРАЗИТСЯ на использующих программах.

4 Компиляция и использование модулей

Модуль компилируется точно таким же как и обы­чные программы. Можно компилировать из интегриро­ванной среды или с помощью компилятора командной стро­ки. Но так как модуль не является непосредственно выпол­няемой единицей, то в результате его компиляции образует­ся внешний файл с расширением .TPU (Turbo Pascal Unit). При этом имя файла до расширения .tpu совпадает с именем исходного файла (текста на паскале) до расширения .pas. Чтобы получить доступ к интерфейсным объек­там модуля, необходимо в программе в предложении использования записать имя нужного TPU-файла. Об­щий вид предложения использования:

uses

U1, U2, U3;

где uses - служебное слово, U1, U2, U3 - идентификаторы ис­пользуемых модулей. Это предложение должно быть записано сразу после заголовка программы. Если модуль использует объекты другого модуля, то такая специ­фикация должна следовать сразу после служебного слова interface.

При наличии предложения использования в данной про­грамме считаются известными все описания из интерфей­сной части подключенного модуля. К интерфейсным объектам модуля можно обращаться в программе точно так же, как если бы они были описаны в самой этой программе.

Следующий пример иллюстрирует использование модуля CmplVals:

program UsingComplex;

uses CmplVals;

var

C1, C2, C3 : Complex;

begin

InitC(1,2,C1); InitC(3,4,C2); MultC(C1,C2,C3); WriteC(C3);

DivC(C1,C2,C3); WriteC(C3)

end.

Необходимо особо отметить следующие важные момен­ты, связанные с использованием модулей:

1. Может случиться так, что некоторые идентификаторы интерфейсной части используемого модуля частично совпадают с идентификаторами использующей программы. В этом случае действует следующее правило видимости имен: ин­терфейсные идентификаторы модуля, указанного первым в uses-списке, образуют самый внешний блок программы; интерфейсные идентификаторы второго модуля образуют блок, вложенный в первый блок, и т.д. Если, например, в программе имеется спецификация вида uses А, В; то вложенность блоков выглядит так:

идентификаторы модуля А

идентификаторы модуля В

идентификаторы

программы

Таким образом, идентификаторы внешнего блока про­граммы будут "экранировать" одноименные идентифика­торы модулей А и В; аналогично, идентификаторы модуля А будут перекрыты одноименными идентификаторами модуля В.

Однако, существует возможность доступа к идентификаторам интерфейса используемого модуля несмотря на наличие в программе одноименных идентификаторов. Пусть имеется следую­щий модуль:

unit А;

interface

var

X : real; implementation

end.

Далее, пусть программа, использующая этот модуль, так­же содержит переменную X:

program Р; uses А;

var

X : integer;

begin

end.

Для того чтобы в программе Р иметь доступ к интерфейс­ной переменной X из модуля А, необходимо указать состав­ное имя, структура которого похожа на селектор поля за­писи: А.Х

Здесь А - имя модуля, X - идентификатор его интерфейс­ной переменной. В этом случае конфликт имен снимается, так как простое указание имени X будет означать обраще­ние к переменной из программы Р, на­пример:

А.Х := Round(X);

2. Возможны случаи косвенных использований. Например, пусть имеются два модуля:

unit A; unit B;

interface interface . . . uses A;

end. . . .

end.

Если некоторая программа использует модуль В, то в со­ответствующей спецификации использования необходимо указать только модули, НЕПОСРЕДСТВЕННО используе­мые в программе. В данном примере достаточной являет­ся следующая спецификация:

program P;

uses В;

end.

(Необходимо отметить, что в фирменной документации по системе Turbo Pascal можно встретить и противопо­ложное требование, согласно которому в спецификации использования должны быть указаны ВСЕ модули, прямо или косвенно используемые программой. Однако, из прак­тики видно, что компилятор правильно обрабатывает программы, в спецификации использования которых ука­заны только модули, непосредственно используемые ею).

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

unit A; unit В;

interface interface uses В; uses А;

end. end.

Однако допускается взаимное использования модулей, поз­воляющее ослабить указанное ограничение. В этом случае спецификация использования может указываться в разделе реализации. Такая возможность используется сравнительно редко поэтому мы ее рассматривать не будем.

4. Если в модуле имеется раздел инициализации, то операто­ры из этого раздела будут выполнены ДО начала вы­полнения программы, в которой используется данный мо­дуль. Если программа использует несколько модулей, то их разделы инициализации будут выполнены в том же по­рядке, в котором эти модули перечислены в специфика­ции использования.