Косвенные и перекрестные ссылки на модули
Вначале рассмотрим случай косвенного использования модуля. Например, пусть имеются два модуля:
unit A; interface ....... end. | unit B; interface uses A; ....... end. |
Здесь, как ясно видно, модуль В использует модуль А, и если в вызывающей программе будет использовано предложение uses вида:
USES B; = Uses B,A;
то все равно при этом неявно(косвенно) будет использован и модуль А, и он, естественно, будет тоже прикомпонован к вызывающей программе.
Для случая перекрестных ссылок вначале рассмотрим следующий пример. Пусть имеются два следующих модуля:
unit A; interface uses B; ....... end. | unit B; interface uses A; ....... end. |
Здесь модули А и В с помощью косвенной рекурсии обращаются сами к себе. Такие отношения между модулями недопустимы, т.е. недопустимо прямое или косвенное обращение модуля к самому себе через интерфейсную секцию.
В этом случае можно завести третий модуль и поместить в него все те типы, переменные, константы, процедуры и функции из первых двух модулей, которые ссылаются друг на друга. После этого надо удалить эти общие ресурсы из первых двух модулей и подключить заведенный третий модуль.
Таким приемом часто пользуются, когда нужно какие-то типы, переменные и константы сделать общими для программы и/или разных модулей. Проблема здесь в том, что само понятие "модуль" было задумано для того, чтобы сделать модули независимыми от глобальных переменных в основной программе. Выход в данном случае состоит в том, чтобы создать модуль из одних только этих глобальных описаний и подключать его везде, где требуется обращение к общим переменным, типам и константам:
unit C;
interface
type
t=record
s:string; i:integer; end; var v:t; const m=25; implementation end.
|
|
Однако допускаются перекрестные связи между модулями через секции реализации.
В следующей программе показаны два модуля, которые "используют" друг друга. Основная программа Message использует модуль с именем Display. Модуль Display содержит в своей интерфейсной секции одну процедуру WriteXY, которая имеет три параметра: пару координат (x,y) и сообщение для вывода на экран. WriteXY перемещает курсор в точку (x,y) и выводит там сообщение. В противном случае она вызывает простую программу обработки ошибки.
Пока мы не видим здесь ничего интересного: процедура WriteXY просто используется вместо процедуры Write. Однако далее, когда программа обработки ошибки будет выводить сообщение на экран, начинаются перекрестные ссылки (ведь при этом она снова использует WriteXY). Таким образом, мы имеем процедуру WriteXY, вызывающую процедуру обработки ошибки SwapError, которая в свою очередь вызывает WriteXY для вывода сообщения на экран.
Пусть основная программа Message очищает экран и выполняет три обращения к процедуре WriteXY:
program Message;
{ выводит текст, используя WriteXY }
uses
WinCrt, Display;
begin
ClrScr;
WriteXY(1, 1, 'Левый верхний угол экрана');
WriteXY(100, 100, 'За пределами экрана');
WriteXY(81 - Lenght('Снова в экран..'), 15,'Снова в экран..');
end.
Взгляните на координаты (x,y) при втором обращении к процедуре WriteXY. В точке с координатами (100,100) на 80х25-символьном экране вывести текст невозможно. Давайте теперь посмотрим, как работает процедура WriteXY. Далее приведен текст исходного кода модуля Display, в котором содержится процедура WriteXY. Если координаты (x,y) являются допустимыми, она выводит на экран сообщение. В противном случае она выводит сообщение об ошибке.
unit Display;
{ содержит простую программу вывода информации на экран }
interface
procedure WriteXY(X,Y : integer, Message : string);
implementation
uses
Crt, Error;
procedure WriteXY(X,Y : integer, Message : string);
begin
if (X in [1..80] and Y in [1..25]
then
begin
Gotoxy(X,Y);
Write(Message);
end;
else
ShowError('Неверные координаты в процедуре WriteXY');
end;
end.
Процедура ShowError, вызываемая в процедуре WriteXY, показана в приведенном далее исходном коде модуля Error. Она всегда выводит сообщение об ошибке на 25-й строке экрана.
unit Error; {содержит простую программу сообщения об ошибке}
interface
procedure ShowError(ErrMsg : string);
implementation
uses
Display;
procedure ShowError(ErrMsg :string);
begin
WriteXY(1,25, 'Ошибка: '+ ErrMsg);
end;
end.
Обратите внимание, что операторы uses в секции реализации обоих модулей (Display и Error) ссылаются друг на друга. Эти два модуля могут ссылаться друг на друга в секции реализации благодаря тому, что Borland Pascal может для обеих модулей выполнять полную компиляцию интерфейсных секций. Другими словами, компилятор правильно воспринимает ссылку на частично скомпилированный модуль A в секции реализации модуля В, если интерфейсные секции модуля A и модуля В не зависят друг от друга (и, следовательно, строго соблюдаются правила Паскаля, касающиеся порядка описания).
Дата добавления: 2016-05-28; просмотров: 1610;