Справочное руководство Ada 2005
3.9.4 Типы интерфейсов
Тип интерфейса — это абстрактный помеченный тип, предоставляющий ограниченную форму множественного наследования. Помеченный тип, тип задачи или защищённый тип могут иметь один или несколько типов интерфейсов в качестве предков.
Синтаксис
interface_type_definition ::=
[limited | task | protected | synchronized] interface [and interface_list]
[limited | task | protected | synchronized] interface [and interface_list]
Статическая семантика
Тип интерфейса (также называемый интерфейсом) — это специфический абстрактный помеченный тип, определённый с помощью interface_type_definition.
Интерфейс со служебными словами limited, task, protected или synchronized в своём определении соответственно называется ограниченным интерфейсом, интерфейсом задачи, интерфейсом защищённого типа или синхронизированным интерфейсом. Кроме того, все интерфейсы задач и защищённых типов являются синхронизированными интерфейсами, а все синхронизированные интерфейсы являются ограниченными интерфейсами.
Задача или защищённый тип, производные от интерфейса, являются помеченными типами. Такие помеченные типы называются синхронизированными помеченными типами, как и синхронизированные интерфейсы и частные расширения, объявление которых включает служебное слово synchronized.
Интерфейс задачи — это абстрактный тип задачи. Интерфейс защищённого типа — это абстрактный защищённый тип.
Тип интерфейса не имеет компонентов.
interface_subtype_mark в interface_list задаёт тип-предок; его тип является типом-предком. Тип интерфейса наследует определённые пользователем примитивные подпрограммы от каждого типа-предка так же, как производный тип наследует определённые пользователем примитивные подпрограммы от своих типов-предков (см. 3.4).
Правила легальности
Все определённые пользователем примитивные подпрограммы типа интерфейса должны быть абстрактными подпрограммами или пустыми процедурами.
Тип подтипа, указанного в interface_list, должен быть типом интерфейса.
Производный тип от неограниченного интерфейса должен быть неограниченным.
Интерфейс, производный от интерфейса задачи, должен включать служебное слово task в своём определении; любой другой тип, производный от интерфейса задачи, должен быть частным расширением или типом задачи, объявленным в объявлении задачи (см. 9.1).
Интерфейс, производный от интерфейса защищённого типа, должен включать служебное слово protected в своём определении; любой другой тип, производный от интерфейса защищённого типа, должен быть частным расширением или типом защищённого типа, объявленным в объявлении защищённого типа (см. 9.4).
Интерфейс, производный от синхронизированного интерфейса, должен включать одно из служебных слов task, protected или synchronized в своём определении; любой другой тип, производный от синхронизированного интерфейса, должен быть частным расширением, типом задачи, объявленным в объявлении задачи, или типом защищённого типа, объявленным в объявлении защищённого типа.
Ни один тип не может быть производным как от интерфейса задачи, так и от интерфейса защищённого типа.
Помимо мест, где обычно применяются правила легальности (см. 12.3), эти правила применяются также в частной части экземпляра генерического модуля.
Динамическая семантика
Выполнение interface_type_definition не оказывает никакого эффекта.
ПРИМЕЧАНИЯ
79 Неограниченные типы интерфейсов имеют предопределённые неоперативные операторы равенства. Эти операторы могут быть переопределены с помощью определённых пользователем абстрактных операторов равенства. Такие операторы будут тогда требовать явного переопределения для любого неабстрактного потомка интерфейса.
Примеры
Пример ограниченного интерфейса и синхронизированного интерфейса, расширяющего его:
type Queue is limited interface;
procedure Append(Q : in out Queue; Person : in Person_Name) is abstract;
procedure Remove_First(Q : in out Queue;
Person : out Person_Name) is abstract;
function Cur_Count(Q : in Queue) return Natural is abstract;
function Max_Count(Q : in Queue) return Natural is abstract;
-- См. 3.10.1 для Person_Name.
procedure Append(Q : in out Queue; Person : in Person_Name) is abstract;
procedure Remove_First(Q : in out Queue;
Person : out Person_Name) is abstract;
function Cur_Count(Q : in Queue) return Natural is abstract;
function Max_Count(Q : in Queue) return Natural is abstract;
-- См. 3.10.1 для Person_Name.
Queue_Error : exception;
-- Append вызывает Queue_Error, если Count(Q) = Max_Count(Q)
-- Remove_First вызывает Queue_Error, если Count(Q) = 0
-- Append вызывает Queue_Error, если Count(Q) = Max_Count(Q)
-- Remove_First вызывает Queue_Error, если Count(Q) = 0
type Synchronized_Queue is synchronized interface and Queue; -- см. 9.11
procedure Append_Wait(Q : in out Synchronized_Queue;
Person : in Person_Name) is abstract;
procedure Remove_First_Wait(Q : in out Synchronized_Queue;
Person : out Person_Name) is abstract;
procedure Append_Wait(Q : in out Synchronized_Queue;
Person : in Person_Name) is abstract;
procedure Remove_First_Wait(Q : in out Synchronized_Queue;
Person : out Person_Name) is abstract;
...
procedure Transfer(From : in out Queue'Class;
To : in out Queue'Class;
Number : in Natural := 1) is
Person : Person_Name;
begin
for I in 1..Number loop
Remove_First(From, Person);
Append(To, Person);
end loop;
end Transfer;
To : in out Queue'Class;
Number : in Natural := 1) is
Person : Person_Name;
begin
for I in 1..Number loop
Remove_First(From, Person);
Append(To, Person);
end loop;
end Transfer;
Это определяет интерфейс очереди, определяющий очередь людей. (Аналогичный дизайн можно создать для определения любого типа очереди, просто заменив Person_Name соответствующим типом.) Интерфейс очереди имеет четыре операция, Append, Remove_First, Cur_Count и Max_Count. Также показан текст подпрограммы Transfer, обрабатывающей операции класса.
Интерфейс Synchronized_Queue наследует четыре операция от Queue и добавляет две дополнительные операции, которые ожидают, если необходимо, вместо того, чтобы вызывать исключение Queue_Error. Этот синхронизированный интерфейс может быть реализован только задачей или защищённым типом, и, таким образом, гарантирует безопасный конкурентный доступ.
Пример использования интерфейса:
type Fast_Food_Queue is new Queue with record ...;
procedure Append(Q : in out Fast_Food_Queue; Person : in Person_Name);
procedure Remove_First(Q : in out Fast_Food_Queue; Person : in Person_Name);
function Cur_Count(Q : in Fast_Food_Queue) return Natural;
function Max_Count(Q : in Fast_Food_Queue) return Natural;
procedure Append(Q : in out Fast_Food_Queue; Person : in Person_Name);
procedure Remove_First(Q : in out Fast_Food_Queue; Person : in Person_Name);
function Cur_Count(Q : in Fast_Food_Queue) return Natural;
function Max_Count(Q : in Fast_Food_Queue) return Natural;
...
Cashier, Counter : Fast_Food_Queue;
...
-- Добавить Георгия (см. 3.10.1) в очередь кассира:
Append (Cashier, George);
-- После оплаты переместить Георгия в очередь очереди сэндвичей:
Transfer (Cashier, Counter);
...
-- Добавить Георгия (см. 3.10.1) в очередь кассира:
Append (Cashier, George);
-- После оплаты переместить Георгия в очередь очереди сэндвичей:
Transfer (Cashier, Counter);
...
Интерфейс, такой как Queue, может быть непосредственно использован в качестве родительского типа нового типа (как показано здесь) или может быть использован в качестве предка, когда тип является производным. В любом случае примитивные операции интерфейса наследуются. Для Queue, необходимо предоставить реализацию четырёх унаследованных процедур.
Пример интерфейса задачи:
type Serial_Device is task interface; -- см. 9.1
procedure Read (Dev : in Serial_Device; C : out Character) is abstract;
procedure Write(Dev : in Serial_Device; C : in Character) is abstract;
procedure Read (Dev : in Serial_Device; C : out Character) is abstract;
procedure Write(Dev : in Serial_Device; C : in Character) is abstract;
Интерфейс Serial_Device имеет две операции, предназначенные для реализации в виде задачных входов (см. 9.1).