Ada (798525), страница 18
Текст из файла (страница 18)
Спецификацияописывает интерфейс настраиваемого модуля, а тело содержит детали его внутреннейреализации.Однажды скомпилированные настраиваемые модули помещаются в библиотеку Ады и могутбыть указаны в инструкции спецификатора совместности контекста with в другихкомпилируемых модулях. При этом, следует заметить, что настраиваемые модули не могут бытьуказаны в инструкции спецификатора использования контекста use.После указания настраиваемого модуля в спецификаторе контекста with, программный модуль(подпрограмма, пакет или другой настраиваемый модуль) осуществляет конкретизациюнастраиваемого модуля, то есть, создает экземпляр настроенного модуля из настраиваемогомодуля. После этого, экземпляр настроенного модуля (конкретизированная подпрограмма илипакет) может быть сохранен в библиотеке Ады для последующего использования.В качестве простого примера использования настраиваемогоконкретизацию стандартного настраиваемого пакета Integer_IO:with Ada.Text_IO;модуля,рассмотримuse Ada.Text_IO;package Int_IO is new Integer_IO(Integer);Получившийся экземпляр настроенного модуля (пакет Int_IO), в последствии, может бытьпомещен в инструкции спецификации контекста with и use любого программного модуля.Следует заметить, что стандартный настраиваемый пакет Integer_IO таким же образом можетбыть конкретизирован при использовании других типов.with Ada.Text_IO;with Accounts;use Ada.Text_IO;use Accounts;package Account_No_IO is new Integer_IO(Account_No);9.1.1 Настраиваемые подпрограммыРассмотрим простой пример описания настраиваемой подпрограммы.
Однаждыскомпилированная, она в последствии может быть помещена в инструкцию спецификаторасовместности контекста with в других программных модулях. Напомним также, чтонастраиваемый модуль нельзя указывать в инструкции спецификатора использования контекстаuse.Спецификация модуля настраиваемой подпрограммы содержит ключевое слово generic, послекоторого следует список формальных параметров настройки и далее - спецификация процедуры:generictype Element is private; -- Element - это параметр настраиваемой-- подпрограммыprocedure Exchange(A, B : in out Element);Тело настраиваемой процедуры описывает реализацию алгоритма работы процедуры ипредставляется как отдельно компилируемый модуль. Примечательно, что оно идентично ненастраиваемой версии.procedure Exchange(A, B: in out Element) isTemp : Element;beginT := Temp;T := B;B := Temp;end Exchange;Код, показанный выше, является простым шаблоном для процедуры, которая может бытьреально создана.
Следует обратить внимание на то, что этот код не может быть непосредственновызван. Это подобно описанию типа, поскольку не производится никакого распределенияпространства памяти или генерации машинного кода.Для создания реальной процедуры, то есть, экземпляра процедуры которую можно вызвать,необходимо выполнить конкретизацию настраиваемой процедуры:procedure Swap is new Exchange(Integer);Следует заметить, что в показанном выше примере конкретизация настраиваемой процедурыосуществлена с использованием простого позиционного сопоставления формального ифактического параметров настройки. В дополнение к позиционному сопоставлению, Адапозволяет использовать именное сопоставление формальных и фактических параметровнастройки (при большом количестве параметров настройки, именное сопоставление улучшаетчитабельность). Показанную выше конкретизацию настраиваемой процедуры можноосуществить с помощью использования именного сопоставления следующим образом:procedure Swap is new Exchange(Element => Integer);Теперь мы имеем процедуру Swap которая меняет местами переменные целого типа Integer.Здесь, Integer является фактическим параметром настройки, а Element - формальнымпараметром настройки.Процедура Swap может быть вызвана (и она будет вести себя) как будто она была описанаследующим образом:procedure Swap (A, B: in out Integer) isTemp : Integer;begin...end Swap;Таких процедур Swap можно создать столько, сколько необходимо.procedure Swap is new Exchange(Character);procedure Swap is new Exchange(Element => Account); -- ассоциация по имениВ этом случае будет нормально использоваться совмещение имен процедур.
Компилятор будетопределять к какой конкретно процедуре производится вызов используя информацию о типепараметра.9.1.2 Настраиваемые пакетыПакеты также могут быть настраиваемыми. Следующая спецификация настраиваемого пакетадостаточно традиционна:generictype Element is private; -- примечательно, что это параметр-- настройкиpackage Stacks isprocedure Push(E : in Element);procedure Pop(E : out Element);function Empty return Boolean;privateThe_Stack : array(1..200) of Element;top: Integer range 0..200 := 0;end Stacks;Сопутствующее тело пакета может иметь подобный вид:package body Stacks isprocedure Push(E : in Element) is...procedure Pop(E : out Element) is...function Empty return Boolean is...end Stacks;В качестве элемента настройки, необходимо просто указать любой экземпляр типа данных.9.1.3 Дочерние настраиваемые модулиНастраиваемые пакеты, подобно обычным пакетам Ады, могут иметь дочерние модули.
Приэтом, следует заметить, что такие дочерние модули также должны быть настраиваемымимодулями.В качестве примера, предположим, что нам необходимо расширить настраиваемый пакет Stacks,который был показан в примере выше (см. 9.1.2). Допустим, что нам необходимо добавитьфункцию Top, которая возвращает объект находящийся в вершине стека, но при этом не удаляетего из стека.
Чтобы решить эту задачу, мы можем, для настраиваемого пакета Stacks, описатьдочерний настраиваемый пакет Stacks.Additions. Спецификация Stacks.Additions может выглядетьследующим образом:genericpackage Stacks.Additions isfunction Top return Element;end Stacks.Additions;Примечательно, что дочерний настраиваемый модуль "видит" все компоненты своего родителя,включая все параметры настройки.Тело дочернего настраиваемого модуля Stacks.Additions может иметь следующий вид:package body Stacks.Additions isfunction Top return Element is...end Stacks.Additions;Ниже демонстрируется пример конкретизации настраиваемых модулей Stacks и Stacks.Additions.Конкретизация модуля Stacks формирует пакет Our_Stacks, что имеет вид:withStacks;package Our_Stack is new Stack(Integer);Конкретизация модуля Stacks.Additions формирует пакет Our_Stack_Additions, что имеет вид:withOur_Stack, Stacks.Additions;package Our_Stack_Additions is new Stacks.Additions;Примечательно, что настраиваемый дочерний модуль рассматривается как описанный внутринастраиваемого родителя.9.2 Параметры настройки для настраиваемых модулейСуществует три типа параметров для настраиваемых модулей:•••параметры-типыпараметры-значенияпараметры-подпрограммыНеобходимо заметить, что до настоящего момента в примерах мы рассматривали толькопараметры-типы.9.2.1 Параметры-типыНе смотря на привлекательные свойства настраиваемых модулей, при определении характеразадач, решаемых с помощью настраиваемого модуля, необходимо иметь возможностьнакладывать некоторые ограничения.
Допустим, что некоторые настраиваемые модулипредусматривают возможность суммирования массива чисел. Очевидно, что это характернотолько для чисел, и мы не можем производить суммирование записей. Следовательно, для того,чтобы защититься от конкретизации настраиваемых модулей с указанием не подходящих типовданных, требуется возможность в установке некоторых ограничений. Кроме того, желательночтобы компилятор также мог осуществлять проверку того, что мы не выполняем какие-нибудьне допустимые действия с переменной внутри кода настраиваемого модуля, например, чтобы онне разрешал использовать атрибут 'Pred для записей.Решение таких задач обеспечивается механизмом который основан на виде спецификацииформального параметра-типа.
Таким образом, спецификация формального параметра-типаопределяет категорию типов, которые могут быть использованы при конкретизациинастраиваемого модуля, а также те действия, которые можно осуществлять над формальнымпараметром внутри настраиваемого модуля. Ниже показан общий список вариантовспецификаций формальных параметров-типов и различные ограничения, накладываемые навыбор фактических параметров-типов настраиваемых модулей.type T is limited privatetype T is private-- тип T - любой тип-- тип T - любой не лимитированный типtype T is (<>)-- тип T любой дискретный типtype T is range <>type T is mod <>-- (целочисленный или перечислимый)-- тип T любой целочисленный тип-- тип T любой модульный целочисленный типtype T is digits <>-- тип T любой вещественный тип с плавающей точкойtype T is delta <>-- тип T любой вещественный тип с фиксированной точкойtype T is delta <> digits <> -- тип T любой вещественный децимальный типtype T is access Y;-- тип T любой ссылающийся на Y ссылочный типtype T is access all Y;-- тип T любой "access all Y" ссылочный типtype T is access constant Y; -- тип T любой "access constant Y" ссылочный тип-- примечание: тип Y может быть предварительно описанным--настраиваемым параметромtype T is array(Y range <>) of Z; -- тип T любой неограниченный массив элементов типа Ztype T is array(Y) of Z;-- у которого Y - подтип индекса-- тип T любой ограниченный массив элементов типа Z-- у которого Y - подтип индекса-- примечание: тип Z (тип компонента фактического массива)--должен совпадать с типом формального массива.--если они не являются скалярными типами,--то они оба должны иметь тип--ограниченного или неограниченного массиваtype T is new Y;type T is new Y with private;-- тип T любой производный от Y тип-- тип T любой не абстрактный тэговый тип-- производный от Ytype T is abstract new Y with private;-- тип T любой тэговый тип производный от Ytype T is tagged private;-- тип T любой не абстрактный не лимитированый-- тэговый типtype T is tagged limited private;-- тип T любой не абстрактный тэговый типtype T is abstract tagged private;-- тип T любой не лимитированый тэговый типtype T is abstract tagged limited private; -- тип T любой тэговый типДля того чтобы лучше понять правила управляющие конкретизацией для параметров типамассив, рассмотрим следующий настраиваемый пакет:generictype Item is private;type Index is (<>);type Vector is array (Index range <>) of Item;type Table is array (Index) of Item;package P is .