Spec-Zone.ru › Ada 2005
Справочник Ada 2005

3.9 Типированные типы и расширения типов

Типированные типы и расширения типов поддерживают объектно-ориентированное программирование на основе наследования с расширением и полиморфизмом во время выполнения с помощью операций диспетчеризации.

Статическая семантика

Тип записи или приватный тип, в объявлении которого используется зарезервированное слово tagged, называется типированным типом. Кроме того, тип интерфейса является типированным типом, как и тип задачи или защищенного типа, полученного из интерфейса (см. 3.9.4). При получении типа от типированного типа, как и для любого производного типа, могут быть определены дополнительные примитивные подпрограммы, а унаследованные примитивные подпрограммы могут быть переопределены. Производный тип называется расширением его предшествующих типов или просто расширением типа.
Каждое расширение типа также является типированным типом и является расширением записи или расширением приватного типа некоторого другого типированного типа или неинтерфейсного синхронизированного типированного типа (см. 3.9.4). Расширение записи определяется с помощью derived_type_definition с record_extension_part (см. 3.9.1), которая может включать определение дополнительных компонентов. Расширение приватного типа, которое представляет собой частичный вид расширения записи или синхронизированного типированного типа, может быть объявлено в видимой части пакета (см. 7.3) или в формальной части обобщенного типа (см. 12.5.1).
Объект типированного типа имеет связанный (во время выполнения) тег, который идентифицирует конкретный типированный тип, используемый для первоначального создания объекта. Тег операнда типированного типа T'Class управляет тем, какой тело подпрограммы будет выполнено, когда примитивная подпрограмма типа T применяется к операнду (см. 3.9.2); использование тега для управления тем, какое тело выполнить, называется диспетчеризацией.
Тег конкретного типированного типа идентифицирует full_type_declaration типа, а для расширения типа достаточно для уникальной идентификации типа среди всех потомков одного предка. Если объявление типированного типа встречается в generic_package_declaration, то соответствующие объявления типов в различных экземплярах обобщенного пакета связаны с различными тегами. Для типированного типа, который является локальным для обобщенного тела пакета, и все его предки (если таковые имеются) также локальны для обобщенного тела, язык не определяет, приводят ли повторные инстанциации обобщенного тела к различным тегам.
Существует следующий определенный языком библиотечный пакет:
package Ada.Tags is
pragma Preelaborate(Tags);
type Tag is private;
pragma Preelaborable_Initialization(Tag);
No_Tag : constant Tag;
function Expanded_Name(T : Tag) return String;
function Wide_Expanded_Name(T : Tag) return Wide_String;
function Wide_Wide_Expanded_Name(T : Tag) return Wide_Wide_String;
function External_Tag(T : Tag) return String;
function Internal_Tag(External : String) return Tag;
function Descendant_Tag(External : String; Ancestor : Tag) return Tag;
function Is_Descendant_At_Same_Level(Descendant, Ancestor : Tag)
return Boolean;
function Parent_Tag (T : Tag) return Tag;
type Tag_Array is array (Positive range <>) of Tag;
function Interface_Ancestor_Tags (T : Tag) return Tag_Array;
Tag_Error : exception;
private
... -- не определено языком
end Ada.Tags;
No_Tag — это значение по умолчанию для типа Tag.
Функция Wide_Wide_Expanded_Name возвращает полное расширенное имя первого подтипа конкретного типа, идентифицируемого тегом, заглавными буквами, начиная с корневого библиотечного блока. Результат определяется реализацией, если тип объявлен внутри безымянного block_statement.
Функция Expanded_Name (соответственно, Wide_Expanded_Name) возвращает ту же последовательность графических символов, что и определено для Wide_Wide_Expanded_Name, если все графические символы определены в Character (соответственно, Wide_Character); в противном случае последовательность символов определяется реализацией, но не короче той, что возвращается Wide_Wide_Expanded_Name для того же значения аргумента.
Функция External_Tag возвращает строку, которая должна использоваться во внешнем представлении для данного тега. Вызов External_Tag(S'Tag) эквивалентен attribute_reference S'External_Tag (см. 13.3).
Строка, возвращаемая функциями Expanded_Name, Wide_Expanded_Name, Wide_Wide_Expanded_Name и External_Tag, имеет нижнюю границу 1.
Функция Internal_Tag возвращает тег, который соответствует заданному внешнему тегу, или возбуждает Tag_Error, если заданная строка не является внешним тегом для любого конкретного типа раздела. Tag_Error также возбуждается, если идентифицированный конкретный тип является типом библиотечного уровня, тег которого еще не был создан (см. 13.14).
Функция Descendant_Tag возвращает (внутренний) тег для типа, соответствующего заданному внешнему тегу и являющемуся потомком типа, идентифицированного тегом Ancestor, и имеющим такой же уровень доступности, как и идентифицированный предок. Tag_Error возбуждается, если External не является внешним тегом для такого типа. Tag_Error также возбуждается, если идентифицированный конкретный тип является типом библиотечного уровня, тег которого еще не был создан.
Функция Is_Descendant_At_Same_Level возвращает True, если тег Descendant идентифицирует тип, который является потомком типа, идентифицируемого Ancestor, и находится на том же уровне доступности. В противном случае возвращает False.
Функция Parent_Tag возвращает тег родительского типа типа, тег которого — T. Если тип не имеет родительского типа (то есть он не был объявлен с помощью derived_type_declaration), то возвращается No_Tag.
Функция Interface_Ancestor_Tags возвращает массив, содержащий тег каждого типа-предка интерфейса типа, тег которого — T, кроме самого T. Нижняя граница возвращаемого массива — 1, а порядок возвращаемых тегов не определен. Каждый тег появляется в результате ровно один раз. Если у типа, тег которого — T, нет предков-интерфейсов, возвращается пустой массив.
Для каждого подтипа S типированного типа T (конкретного или универсального), определены следующие атрибуты:
S'Class
S'Class обозначает подтип универсального типа (называемого T'Class в данном Международном стандарте) для класса, укорененного в T (или если S уже обозначает универсальный подтип, то S'Class такой же, как S).
S'Class не ограничен. Однако, если S ограничен, то значения S'Class — только те, которые, при преобразовании в тип T, относятся к S.
S'Tag
S'Tag обозначает тег типа T (или если T — универсальный, то тег корневого типа соответствующего класса). Значение этого атрибута имеет тип Tag.
При заданном prefix X, который является типированным универсальным типом (после любого неявного разыменования), определен следующий атрибут:
X'Tag
X'Tag обозначает тег X. Значение этого атрибута имеет тип Tag.
Существует следующая обобщенная функция, определенная языком:
generic
type T (<>) is abstract tagged limited private;
type Parameters (<>) is limited private;
with function Constructor (Params : not null access Parameters)
return T is abstract;
function Ada.Tags.Generic_Dispatching_Constructor
(The_Tag : Tag;
Params : not null access Parameters) return T'Class;
pragma Preelaborate(Generic_Dispatching_Constructor);
pragma Convention(Intrinsic, Generic_Dispatching_Constructor);
Tags.Generic_Dispatching_Constructor предоставляет механизм создания объекта соответствующего типа только из значения тега. Функция Constructor ожидает создать объект, учитывая ссылку на объект типа Parameters.

Динамическая семантика

Тег, связанный с объектом типированного типа, определяется следующим образом:
  • Тег автономного объекта, компонента или aggregate конкретного типированного типа T идентифицирует T.
  • Тег объекта, созданного аллокатором для типа доступа со специфическим обозначенным типированным типом T, идентифицирует T.
  • Тег объекта универсального типированного типа — это тег его выражения инициализации.
  • Тег результата, возвращаемого функцией, тип результата которой — конкретный типированный тип T, идентифицирует T.
  • Тег результата, возвращаемого функцией с универсальным типом результата, — это тег возвращаемого объекта.
Тег сохраняется при преобразовании типов и при передаче параметров. Тег значения — это тег связанного объекта (см. 6.2).
Tag_Error возбуждается при вызове Descendant_Tag, Expanded_Name, External_Tag, Interface_Ancestor_Tag, Is_Descendant_At_Same_Level или Parent_Tag, если какой-либо переданный тег — No_Tag.
END_OF_DOCUMENT_MARKER
Экземпляр Tags.Generic_Dispatching_Constructor вызывает исключение Tag_Error, если The_Tag не представляет конкретного потомка T или если внутренний мастер (см. 7.6.1) этого потомка также не является мастером экземпляра. В противном случае, он передает вызов примитивной функции, обозначенной формальным Конструктором для типа, идентифицированного The_Tag, передавая Params, и возвращает результат. Любое исключение, сгенерированное функцией, передаётся вверх.

Ошибка выполнения

Если внутренний тег, предоставленный экземпляру Tags.Generic_Dispatching_Constructor или любой подпрограмме, объявленной в пакете Tags, идентифицирует либо тип, который не является библиотечным уровнем и для которого тег не был создан (см. 13.14), или тип, который не существует в разбиении на момент вызова, то выполнение является ошибочным.

Разрешения реализации

Реализация Internal_Tag и Descendant_Tag может вызвать исключение Tag_Error, если в разбиении на момент вызова функции не существует конкретного типа, соответствующего строке External, переданной в качестве параметра, или если такого типа нет, внутренний мастер которого является мастером точки вызова функции.

Рекомендации по реализации

Internal_Tag должен возвращать тег типа, внутренний мастер которого является мастером точки вызова функции.
ПРИМЕЧАНИЯ
64 Тип, объявленный с помощью ключевого слова tagged, обычно должен быть объявлен в спецификации_пакета, чтобы для него можно было объявить новые примитивные подпрограммы.
65 После создания объекта его тег никогда не меняется.
66 Типы, относящиеся к классу, определены с неизвестными дискриминантами (см. 3.7). Это означает, что объекты типа, относящегося к классу, должны быть явно инициализированы (будь то созданные объявлением объекта object_declaration или аллокатором allocator), и что aggregate должны быть явно квалифицированы с помощью конкретного типа, когда их ожидаемый тип относится к классу.
Этот абзац был удалён.
67 Возможность, предоставляемая Tags.Generic_Dispatching_Constructor, иногда известна как фабрика.

Примеры

Примеры типов помеченных записей:
type Point is tagged
record
X, Y : Real := 0.0;
end record;
type Expression is tagged null record;
-- Компоненты будут добавлены каждым расширением


Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API