Алгоритмические языки высокого уровня. Курс лекций
.pdf6. МОДУЛИ И УСТРОЙСТВА
Часто используемые подпрограммы хранятся в виде собственных библиотек. Библиотеки организуются в виде модулей. Для того что- бы использовать библиотеки (модули) достаточно задать в програм- ме описательное предложение
uses <список имен модулей>;
Текст модуля обычно располагается в файле, потом транслируется в файл с расширением *.tpu. На этапе компоновки (сборки) задачи модуль подключается к оттранслированной программе.
Применение модулей позволяет повысить скорость компиляции программы, поскольку модули хранятся в готовом скомпилирован- ном виде и перекомпилируются только при наличии изменений в их исходном тексте. Модули очень удобны для построения собственных процедур и функций, которые могут использоваться разными про- граммами, не требуя никаких переделок. Модульность позволяет создавать программы практически любого размера.
Чтобы подключить модуль к программе, его требуется предвари- тельно скомпилировать. Результат компиляции модуля хранится на диске в отдельном файле с расширением *.tpu.
Описание модулей
Исходный текст каждого модуля хранится в отдельном файле с расширением *.pas. Модуль состоит из секций (разделов). Общая структура модуля имеет вид:
Unit Имя; {Заголовок модуля} Interface {Интерфейсная часть модуля}
{Описание глобальных переменных модуля видимых извне} Implementation {Секция реализации модуля} {Описание локальных (внутренних) элементов модуля} Begin {Секция инициализации модуля}
{Может отсутствовать}
End.
Имя файла, в котором хранится модуль, должно совпадать с име- нем, заданным после ключевого слова Unit.
В интерфейсной секции модуля определяются константы, типы данных, переменные, а также заголовки процедур и функций. Полно- стью же подпрограммы описываются в секции реализации, скрытой от пользователя модуля. Здесь перечисляются используемые модули со словом USES.
131
В секции реализации модуля описываются подпрограммы, заго- ловки которых приведены в интерфейсной части. Заголовок подпро- граммы должен быть идентичным указанному в секции интерфейса и состоять только из ключевого слова Procedure или Function и имени подпрограммы. Для функции также указывается её тип. Кроме того, в этой секции определяются константы, типы данных, перемен- ные и внутренние подпрограммы. Они используются внешними эле- ментами модуля и видны только в части реализации, т.е. из програм- мы, к которой подключен этот модуль, обратиться к ним нельзя.
Секция инициализации предназначена для присваивания на- чальных значений переменным, используемым в модуле или в про- грамме, к которой он подключен. Операторы, расположенные в сек- ции инициализации модуля, выполняются перед операторами основ- ной программы. Если секция инициализации в модуле отсутствует, то в конце ставится END., а слово BEGIN пропускается.
Пример программы
Описание: программа подсчета средних значений двух массивов. {Модуль: подпрограмма вычисления среднего арифметического
массива чисел}
Unit Average_; INTERFACE
Const n=10;
Type mas=array [1..n] of real; Procedure average(x:mas; var av:real); IMPLEMENTATION
Procedure average(x:mas; var av:real); Var i:integer;
Begin av:=0;
for i:=1 to n do av:=av+x[i]; av:=av/n
end;
End.
Список параметров подпрограммы в разделе IMPLEMENTATION указывать не обязательно.
{основная программа – подсчет средних значений двух массивов}
Program Test;
Uses Average_,CRT; Var a,b: mas;
i :integer; av_a, av_b:real;
132
Begin ClrScr;
randomize;{Подключение генератора случайных чисел} for i:=1 to n do begin
a[i]:=random; {Заполнение массивов} b[i]:=random
end;
average(a, av_a); {Подключение процедуры из модуля} average(b, av_b);
writeln(av_a:5:3,' ',av_b:5:3); readln
End.
Кроме собственных библиотек пользователя существуют стан- дартные библиотеки Pascal. Среди этих библиотек можно назвать следующие: System (ввиду исключительной важности подключа- ется автоматически к любой программе и содержит основные под- программы), Dos (обеспечивает интерфейс с программами опера- ционной системы), Crt (содержит средства управления монитором в текстовом режиме), Graph (содержит средства управления мони- тором в графическом режиме), Printer (обеспечивает связь с пе- чатающим устройством), Overlay (содержит средства для созда- ния и управления перекрывающимися/оверлейными программами).
133
7. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
Объектно-ориентированная концепция создания программ заро- дилась примерно в одно и то же время со структурной методологией (в середине 60-х годов прошлого века) и имела аналогичную цель – обеспечение дисциплины программирования при разработке боль-
ших программных комплексов. Объектно-ориентированное про-
граммирование (ООП) – это методология программирования, которая основана на представлении программы в виде совокупности объек- тов, каждый из которых является реализацией определенного класса (типа особого вида), а классы образуют иерархию на принципах на- следуемости. ООП базируется на трех основных понятиях: инкапсу- ляция, наследование и полиморфизм.
Объект – осязаемая сущность, которая четко проявляет свое по- ведение. Не лишен скрытого смысла студенческий ответ: «Объект – это все». Инкапсуляция – это объединение в рамках единого целого (объекта) данных (характеристик объекта) и действий (процедур и функций) по обработке этих данных. В терминах ООП данные назы- ваются полями, а процедуры и функции – методами, т.е. можно ска- зать, что объект состоит из полей и методов. Инкапсуляция позволя- ет в максимальной степени изолировать объект от внешнего окруже- ния. Объект (а точнее – экземпляр объекта) сам «знает» о себе все и «умеет» манипулировать этими знаниями. При этом обмен данными между объектом и программой (или другим объектом) сведен к ми- нимуму.
Наследование – это свойство объектов порождать своих потом- ков. Наследование – это такое отношение между объектами, когда один объект повторяет структуру и поведение другого. Объект- потомок автоматически наследует от родителя все поля и методы, может быть дополнен новыми полями, а методы предка могут быть заменены или дополнены новыми. Объект может иметь сколько угодно потомков, а вот предок может быть только один. Это дает возможность создавать довольно-таки сложную «ветвистую» (древо- видную) иерархическую структуру объектов в программе.
Полиморфизм – это свойство родственных объектов (т.е. объек- тов, имеющих общего родителя) решать схожие задачи разными спо- собами. Поскольку поведение объекта определяется набором его ме- тодов, то программист, изменяя алгоритм того или иного метода,
134
может придавать потомкам специфические свойства, отсутствующие у родителя. Для этого родительский метод должен быть перекрыт новым. В результате объект–родитель и объект–потомок будут со- держать два разных метода, но с одинаковыми именами. В Turbo Pascal полиморфизм достигается не только за счет наследования и перекрытия методов, но и использования виртуальных методов.
7.1. Объектные типы и экземпляры
Переменные объектных типов (экземпляры объектов) представ- ляют собой структурированный (комбинированный) тип данных, яв- ляющийся совокупностью информационных полей (переменных лю- бого типа) и методов (процедур и функций).
Объектные типы описываются в разделе Type программы с ис- пользованием зарезервированного (ключевого) слова object:
Type
<имя объектного типа> = object <информационные поля> объекта (переменные)>
<методы объекта (заголовки процедур и функций)> end;
Опишем объект, который будет представлять собой позицию на графическом экране. Для этого необходимо объявить два поля (X и Y – координаты точки) и несколько методов: для инициализации объекта, получения его координат, уничтожения и т.п.
Type
TLocation = object
X,Y : Word; {Координаты позиции на экране} Procedure Init(InitX, InitY : Integer);
{Инициализация объекта}
Function GetX : Word; {Возвращает координату Х} Function GetY : Word; {Возвращает координату Y} Procedure GetCoords(Var CoordX, CoordY : Word); {Возвращает обе координаты}
Procedure Done; {Уничтожает объект} End;
Поля объекта описываются таким же образом, что и поля записи, а для описания методов объекта используются только заголовки про- цедур и функций. Тела методов всех объектов, объявленных в про- грамме, описываются в разделе реализации процедур и функций про- граммы (в любом месте и в любой последовательности, но обяза- тельно ниже «своего» объекта). Синтаксически реализация метода
135
выглядит так же, как и реализация «обычной» процедуры или функ- ции за одним исключением: перед именем метода через точку необ- ходимо указать имя объекта, которому он принадлежит:
Procedure <Имя объекта>.<Имя метода>(<Формальные парамет-
ры>); <Раздел локальных описаний метода (процедуры)> begin
<Операторная часть метода (тело процедуры)> end;
Описание методов объекта TLocation:
Procedure TLocation.Init(X,Y : Word);
begin
X := InitX;
Y := InitY end;
Function TLocation.GetX : Word; begin
GetX := X end;
Function TLocation.GetY : Word; begin
GetY := Y end;
Procedure TLocation.GetCoords; begin
CoordX := GetX;
CoordY := GetY end;
Procedure TLocation.Done; begin
end;
Замечания: 1) при реализации методов не обязательно повторять весь заголовок подпрограммы, достаточно только имени без списка формальных параметров (как это сделано для метода GetCoords); 2) метод объекта может обращаться не только к полям, но и к другим методам (как это сделано в методе GetCoords); 3) в данном объекте присутствует метод Done (пустой), который «ничего не делает», по- скольку позицию на экране уничтожить нельзя.
7.2.Директивы private и public
Спомощью директивы private при описании объекта можно ограничить область видимости полей и методов. Поля и методы объ-
136
екта, описанные в секции private, будут доступны только в преде- лах той программной единицы (программы или модуля), где описан соответствующий объект. Такие поля и методы принято называть приватными, т.е. если описать объект TLocation следующим обра- зом:
Type
TLocation = object private
X, Y : Word; public
...
end;
и разместить это описание в модуле, то после подключения модуля к программе программист не сможет «напрямую» изменять значения этих полей (X, Y). Он будет вынужден вызывать соответствующие методы. По умолчанию поля и методы, описанные непосредственно за ключевым словом object, считаются общедоступными. Дирек- тива же public просто отменяет действие директивы private, т.е. все последующие поля и методы будут общедоступными.
Директивы private и public могут использоваться в любом порядке сколько угодно раз, но принято при описании объектного типа после зарезервированного слова object объявлять общедос- тупные поля и методы, и только затем после директивы private – приватные.
7.3. Наследование
Если объектный тип создается «на базе» другого существующего объекта, то имя родительского типа должно быть указано в скобках после слова object при описании потомка:
Type
<Потомок> = object(<Родитель>) <Добавленные поля> <Добавленные и переопределенные методы> end;
Такие объекты автоматически наследуют от родителя его поля и методы. Поля могут быть добавлены (но не переопределены), а ме- тоды переопределены и добавлены.
Создадим новый объект – точку на основе существующего объек- та – позиции на графическом экране. Новый объект, кроме коорди- нат, будет характеризоваться еще и цветом, может быть видимым
137
или невидимым, перемещаться по экрану. Для этого нам понадобит- ся добавить два свойства и несколько методов, а также переопреде- лить методы Init и Done:
Type
TPoint = object(TLocation) Clr : Byte; {Цвет}
Visib : Boolean; {Видимость}
Procedure Init (InitX, InitY:Word; InitColor:Byte); {Переопределяем метод инициализации - добавляем цвет} Function GetColor : Byte; {Возвращает цвет}
Function IsVisib : Boolean; {Возвращает видимость} Procedure Show; {Делает видимым}
Procedure Hide; {Делает невидимым}
Procedure ChangeColor(NewColor : Byte); {Меняет цвет} Procedure MoveTo(NewX, NewY : Word);{Перемещает в новую
позицию}
Procedure Done; {Переопределяем для уничтожения объекта} end;
Описание реализации методов:
Procedure TPoint.Init (InitX, InitY:Word; InitColor:Byte);
begin
X := InitX;
Y := InitY;
Clr := InitColor; Visib := False
end;
Этот метод добавляет новую функциональность по сравнению с предыдущим. Первые две строки тела метода повторяют (причем полностью) операторную часть метода Init объекта TLocation, две следующие – новые. И хотя такой вариант переопределения ме- тода тоже работоспособен, в данном случае его можно упростить с помощью такого механизма, как вызов метода непосредственного родителя из метода потомка. Для этого в Turbo Pascal есть специаль- ное зарезервированное слово inherited (в переводе с английско- го – унаследованный).
Procedure |
TPoint.Init |
(InitX, |
InitY:Word; |
Init- |
Color:Byte); |
|
|
|
|
begin |
|
|
|
|
inherited Init(InitX, InitY); Clr := InitColor;
Visib := False end;
138
Вместо слова inherited можно указать имя объекта-родителя:
TLocation.Init(InitX, InitY);
Function TPoint.GetColor : Byte; begin
GetColor := Clr; end;
Procedure TPoint.Show; begin
Graph.PutPixel(X, Y, Clr); Visib := True
end;
Procedure TPoint.Hide; begin
Graph.PutPixel(X, Y, Graph.GetBkColor); Visib := False
end;
Procedure TPoint.IsVisib : Boolean; begin
IsVisib := Visib end;
Procedure TPoint.ChangeColor(NewColor : Byte); begin
Clr := NewColor;
If IsVisib then Show end;
Procedure TPoint.MoveTo(NewX, NewY : Word); Var Status : Boolean;
begin
Status := IsVisib; Hide;
X := NewX;
Y := NewY;
If Status then Show end;
Procedure TPoint.Done; begin
Hide;
Clr := Graph.GetBkColor end;
Дочерний объектный тип «точка» – потомок родительского объ- екта «позиция» создан.
7.4. Полиморфизм
Создадим еще один дочерний объектный тип – потомок объекта TPoint, который будет представлять собой окружность. X и Y пре-
139
вращаются в координаты центра, и добавляется радиус. Для этого придется переопределить методы инициализации, прорисовки и скрытия.
Type
TCircle = object(TPoint) R : Word;
Procedure Init(InitX, InitY, InitR:Word; InitC:Byte); Procedure Show;
Procedure Hide;
Procedure Done;
end;
Procedure TCircle.Init(InitX,InitY,InitR : Word; InitColor
:Byte); begin
inherited Init(InitX, InitY, InitC); R := InitR
end;
Procedure TCircle.Show; begin
Graph.SetColor(Clr); Graph.Circle(X, Y, R); Visib := True
end;
Procedure TCircle.Hide; begin
Graph.SetColor(Graph.GetBkColor); Graph.Circle(X, Y, R);
Visib := False end;
Procedure TCircle.Done; begin
inherited Done; R := 0
end;
Таким образом, мы получили два объекта, методы которых Show и Hide делают одно и то же, но разными способами (полиморфизм). Но если мы создадим экземпляр этого объекта, проинициализируем его, а затем попытаемся переместить вызовом метода MoveTo, кото- рый был унаследован, то переместится точка, а не окружность. Связано это с тем, что при компиляции в машинный код вместо вы- зова подпрограммы транслятор подставляет адрес точки входа в эту подпрограмму. Это же справедливо и для методов, поэтому при трансляции метода MoveTo объекта TPoint будут подставлены ад- реса точек входа методов Show и Hide объекта TPoint. Объект же
140
