Справочник по Ada 2012
3.4 Производные типы и классы
Определение derived_type_definition определяет производный тип (и его первый подтип), характеристики которого производятся от характеристик родительского типа, и, возможно, от родительских типов.
Класс типов — это множество типов, замкнутое относительно вывода; то есть, если родительский тип или родительский тип производного типа принадлежит классу, то и производный тип также принадлежит этому классу. Говоря, что определённая группа типов образует класс, мы говорим, что все производные типа из этого множества наследуют характеристики, определяющие это множество. Более общее понятие категории типов относится к множеству типов, определяющие характеристики которых не обязательно наследуются производными типами; например, ограниченные, абстрактные и интерфейсные типы являются категориями типов, но не классами типов.
Синтаксис
derived_type_definition ::=
[abstract] [limited] new parent_subtype_indication [[and interface_list] record_extension_part]
[abstract] [limited] new parent_subtype_indication [[and interface_list] record_extension_part]
Правила легальности
parent_subtype_indication определяет родительский подтип; его тип является родительским типом. interface_list определяет типы-предков (см. 3.9.4). Производный тип имеет один родительский тип и ноль или более типов-предков.
Тип должен быть полностью определён (см. 3.11.1) перед указанием его в качестве родительского типа в derived_type_definition — full_type_declarationы родительского типа и всех его подкомпонентов должны предшествовать derived_type_definition.
Если существует record_extension_part, производный тип называется расширением записи родительского типа. record_extension_part должен быть предоставлен тогда и только тогда, когда родительский тип является помеченным типом. interface_list должен быть предоставлен только в том случае, если родительский тип является помеченным типом.
Если ключевое слово limited появляется в derived_type_definition, родительский тип должен быть ограниченным типом. Если родительский тип является формальным помеченным типом, то помимо мест, где обычно применяются правила легальности (см. 12.3), это правило применяется также в частях с private в экземпляре генерируемого блока.
Статическая семантика
Первый подтип производного типа является неограниченным, если в объявлении производного типа предоставлена known_discriminant_part, или если родительский подтип является неограниченным. В противном случае ограничение первого подтипа соответствует ограничению родительского подтипа в следующем смысле: оно такое же, как у родительского подтипа, за исключением того, что для ограничения диапазона (явного или неявного) значение каждой границы диапазона заменяется соответствующим значением производного типа.
Первый подтип производного типа исключает нуль (см. 3.10) тогда и только тогда, когда родительский подтип исключает нуль.
Характеристики и неявно объявленные примитивные подпрограммы производного типа определяются следующим образом:
- Если родительский тип или тип-предок принадлежит классу типов, то производный тип также принадлежит этому классу. Следующие множества типов, а также любые более высокие множества, составленные из них, являются классами в этом смысле, и поэтому характеристики, определяющие эти классы, наследуются производными типами от своих родительских или типов-предков: целые со знаком, модульные целые, обычные фиксированные, десятичные фиксированные, числа с плавающей точкой, перечисления, булевы, символы, доступ к константам, общий доступ к переменной, доступ к переменной конкретного пула, доступ к подпрограмме, массив, строка, составной тип (не массив), неограниченный, не помеченный запись, помеченный, задача, защищённый и синхронизированный помеченный.
- Если родительский тип является элементарным типом или массивом, то множество возможных значений производного типа является копией множества возможных значений родительского типа. Для скалярного типа базовый диапазон производного типа такой же, как у родительского типа.
- Если родительский тип является составным типом, отличным от массива, то компоненты, защищённые подпрограммы и входы, которые объявлены для производного типа, следующие:
Дискриминанты, заданные новым known_discriminant_part, если он есть; в противном случае каждый дискриминант родительского типа (неявно объявленный в том же порядке со спецификациями) — в последнем случае дискриминанты называются унаследованными, или если они неизвестны в родительском типе, они также неизвестны в производном типе;
Каждый недискриминантный компонент, вход и защищённая подпрограмма родительского типа, неявно объявленные в том же порядке с теми же объявлениями; эти компоненты, входы и защищённые подпрограммы называются унаследованными;
Каждый компонент, объявленный в record_extension_part, если таковой имеется.
Объявления компонентов, защищённых подпрограмм и входов, явные или неявные, происходят непосредственно внутри декларативной области типа, в указанном выше порядке, после родительского subtype_indication.
- Этот абзац был удалён.
- Для каждого предопределённого оператора родительского типа существует соответствующий предопределённый оператор производного типа.
- Для каждой пользовательской примитивной подпрограммы (кроме пользовательского оператора равенства — см. ниже) родительского типа или типа-предшественника, уже существующей в месте derived_type_definition, существует соответствующая унаследованная примитивная подпрограмма производного типа с тем же определяющим именем. Пользовательские примитивные операторы равенства родительского типа и любых типов-предшественников также наследуются производным типом, за исключением случая, когда производный тип является не ограниченным расширением записи, и унаследованный оператор имел бы профиль, соответствующий профилю соответствующего предопределённого оператора равенства; в этом случае пользовательский оператор равенства не наследуется, а скорее включается в реализацию предопределённого оператора равенства расширения записи (см. 4.5.2).
Профиль унаследованной подпрограммы (включая унаследованную константу перечисления) получается из профиля соответствующей (пользовательской) примитивной подпрограммы родительского или типа-предшественника после систематической замены каждого подтипа её профиля (см. 6.1), который является родительским или типом-предшественником, кроме тех подтипов, которые найдены в обозначенном профиле access_definition, соответствующим подтипом производного типа. Для данного подтипа родительского или типа-предшественника соответствующий подтип производного типа определяется следующим образом:
Если в объявлении производного типа нет ни known_discriminant_part, ни record_extension_part, то соответствующий подтип имеет ограничение, соответствующее (как определено выше для первого подтипа производного типа) ограничению данного подтипа.
Если производный тип является расширением записи, то соответствующий подтип — это первый подтип производного типа.
Если производный тип имеет новый known_discriminant_part, но не является расширением записи, то соответствующий подтип ограничен теми значениями, которые при преобразовании к родительскому типу принадлежат данному подтипу (см. 4.6).
В профиле унаследованной подпрограммы те же формальные параметры имеют default_expressionы. Любой несоответствие типов, вызванное систематической заменой родительского или типа-предшественника производным типом, обрабатывается как часть обычного преобразования типов, связанного с передачей параметров — см. 6.4.1.
Если примитивная подпрограмма родительского или типа-предшественника видна в месте derived_type_definition, то соответствующая унаследованная подпрограмма неявно объявляется сразу после derived_type_definition. В противном случае унаследованная подпрограмма неявно объявляется позже или вообще не объявляется, как поясняется в 7.3.1.
Производный тип также может быть определён с помощью private_extension_declaration (см. 7.3) или formal_derived_type_definition (см. 12.5.1). Такой производный тип является частичным представлением соответствующего полного или фактического типа.
Все числовые типы являются производными типами, так как они неявно производятся от соответствующего корневого числового типа (см. 3.5.4 и 3.5.6).
Динамическая семантика
Разработка derived_type_definition создает производный тип и его первый подтип, и состоит из разработки subtype_indication и record_extension_part, если таковой имеется. Если subtype_indication зависит от дискриминанта, то вычисляются только те выражения, которые не зависят от дискриминанта.
Для выполнения вызова унаследованной подпрограммы выполняется вызов соответствующей примитивной подпрограммы родительского или прародительского типа; обычное преобразование каждого фактического параметра в подтип соответствующего формального параметра (см. 6.4.1) также выполняет любое необходимое преобразование типов. Если тип результата унаследованной подпрограммы — это производный тип, результат вызова подпрограммы родительского или прародительского типа преобразуется в производный тип, или в случае нулевого расширения расширяется до производного типа, используя эквивалент extension_aggregate с исходным результатом в качестве ancestor_part и нулевым записями в качестве record_component_association_list.
ПРИМЕЧАНИЯ
16 Классы замкнуты относительно производности — любой класс, содержащий тип, также содержит его производные. Операции, доступные для данного класса типов, доступны для производных типов в этом классе.
17 Вычисление унаследованной перечислительной литералы эквивалентно вычислению соответствующей перечислительной литералы родительского типа, а затем преобразованию результата в производный тип. Это следует из их эквивалентности беспараметрическим функциям.
18 Обобщенная подпрограмма не является подпрограммой и, следовательно, не может быть примитивной подпрограммой и не может быть унаследована производным типом. С другой стороны, экземпляр обобщенной подпрограммы может быть примитивной подпрограммой и, следовательно, может быть унаследован.
19 Если родительский тип — это тип доступа, то родительский и производный тип используют один и тот же пул памяти; для производного типа существует значение доступа null, и это неявное начальное значение для типа. См. 3.10.
20 Если родительский тип — это булевый тип, предопределенные реляционные операторы производного типа возвращают результат предопределенного типа Boolean (см. 4.5.2). Если родительский тип — это целочисленный тип, правый операнд предопределенного оператора возведения в степень имеет предопределенный тип Integer (см. 4.5.6).
21 Любые дискриминанты родительского типа либо все наследуются, либо полностью заменяются новым набором дискриминантов.
22 Для унаследованной подпрограммы подтип формального параметра производного типа не обязательно должен иметь какие-либо общие значения с первым подтипом производного типа.
23 Если ключевое слово abstract указано в объявлении типа, тип является абстрактным (см. 3.9.3).
24 Тип интерфейса, у которого есть прародительский тип «производный от» этого типа. Однако derived_type_definition никогда не определяет тип интерфейса.
25 Недопустимо, чтобы родительский тип derived_type_definition был синхронизированным помеченным типом.
Примеры
Примеры объявлений производных типов:
type Local_Coordinate is new Coordinate; -- два разных типа
type Midweek is new Day range Tue .. Thu; -- см. 3.5.1
type Counter is new Positive; -- тот же диапазон, что и Positive
type Midweek is new Day range Tue .. Thu; -- см. 3.5.1
type Counter is new Positive; -- тот же диапазон, что и Positive
type Special_Key is new Key_Manager.Key; -- см. 7.3.1
-- унаследованные подпрограммы имеют следующие спецификации:
-- procedure Get_Key(K : out Special_Key);
-- function "<"(X,Y : Special_Key) return Boolean;
-- унаследованные подпрограммы имеют следующие спецификации:
-- procedure Get_Key(K : out Special_Key);
-- function "<"(X,Y : Special_Key) return Boolean;