Ада-95. Компилятор GNAT

       

Производные типы


Мы уже рассмотрели, что подтипы остаются совместимыми со своими базовыми типами. Однако, нам может понадобиться создать абсолютно новый тип, который не будет ассоциироваться ни с каким другим типом вообще, в том числе и с оригинальным типом. Такая концепция типа сильно отличается от того, что принято в других языках программирования, и, даже, в прародителе Ады - Паскале.

Для выполнения поставленной задачи, мы производим новый тип от другого типа, используя подобный синтаксис:

type Child_Type is new Parent_Type;

Такое описание создает новый тип данных - Child_Type, при этом Parent_Type - это тип-предок для типа Child_Type, а тип Child_Type - это производный тип от типа Parent_Type.

В данном случае, тип Child_Type будет обладать такими же характеристиками что и его тип-предок Parent_Type: у него такой же диапазон допустимых значений как и у типа-предка, для него допустимы те же операции, которые допустимы для типа-предка (говорят, что тип Child_Type унаследовал операции от типа-предка Parent_Type).

Однако, в этом случае, производный тип Child_Type - это абсолютно самостоятельный и независимый тип данных. Он не совместим ни с каким другим типом, включая тип Parent_Type, от которого он был произведен, и другими типами, производными от типа Parent_Type. Это подразумевает, что при необходимости комбинирования значений типа Child_Type

со значениями типа Parent_Type требуется выполнять преобразование типов. В Аде, разрешается выполнять преобразование значений производного типа в значения типа-предка и наоборот.

Для того, чтобы преобразовать значение одного типа в значение другого типа необходимо указать имя типа к которому требуется выполнить преобразование:

Parent : Parent_Type; Child : Child_Type := Child_Type (Parent); -- конвертирует значение Parent, -- имеющее тип Parent_Type -- в значение типа Child_Type



Описание производного типа может указывать ограничение диапазона значений типа-предка, например:

type Child_Type is new Parent_Type range Lowerbound..Upperbound;

<


В этом случае диапазон значений производного типа Child_Type будет ограничен значениями нижней границы диапазона (Lowerbound) и верхней границы диапазона (Upperbound).

Механизм производства новых типов данных из уже существующих типов позволяет создавать целые семейства родственных типов, которые обычно называют классами. Так, например, тип Integer принадлежит к целому классу целочисленных типов. Класс целочисленных типов является, в свою очередь, подмножеством более обширного класса дискретных типов.

Основной смысл использования производных типов заключается в том, что для определенного типа данных уже существует определенный набор примитивных операций и этот набор операций можно унаследовать от такого типа при производстве от него нового типа данных.

Можно создать новый тип данных и затем описать для него идентичный набор операций. Однако, при производстве нового типа данных от уже существующего типа, производный тип автоматически наследует версии примитивных операций, описанные для типа-предка. Таким образом, нет необходимости переписывать код заново.

Например, класс дискретных типов предусматривает атрибут 'First, который наследуется всеми дискретными типами. Класс целочисленных типов добавляет к унаследованным от класса дискретных типов операциям знак операции арифметического сложения "+". Эти механизмы более полно рассматриваются при обсуждении тэговых типов.

Производные типы используются в случаях когда моделирование определенного объекта предполагает, что тип-предок не соответствует нашим потребностям, или тогда, когда мы желаем разделить объекты в различные, несмешиваемые классы.

type Employee_No is new Integer; type Account_No is new Integer range 0..999_999;

Здесь Employee_No и Account_No различные и не смешиваемые типы, которые нельзя комбинировать между собой без явного использования преобразования типов. Производные типы наследуют все операции объявленные для базового типа. Например, если была объявлена запись которая имела процедуры Push и Pop, то производный тип автоматически унаследует эти процедуры.



Другое важное использование производных типов - это создание переносимого кода. Ада разрешает нам создавать новые уровни абстракции, на один уровень выше чем, скажем, абстракция целого числа на последовательности битов.

Это определяется использованием производных типов, без типа-предка.

type Name is range <некоторый_диапазон_значений>;

Например,

type Data is range 0..2_000_000;

В этом случае ответственность, за выбор подходящего размера для целого, ложится на компилятор. Таким образом, для PC, этот размер может быть 32 бита, что эквивалентно типу Long_Integer, а для рабочей станции Unix, этот размер можт остаться равным 32-битному целому, но это будет эквивалентно типу Integer. Такое предоставление компилятору возможности выбирать освобождает программиста от обязанности выбирать. Поэтому перекомпиляция программы на другой машине не требует изменения исходного текста.


Содержание раздела