logo search
Языки программирования

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

Вторая интерпретация отношения между двумя аналогичными типами состо­ит в том, что они представляют разные типы, которые не могут использовать­ся вместе. В языке Ada такие типы называются производными (derived) типами и обозначаются в определении словом new:

type Derived_Dharacter is new Character;

C: Character;

D: Derived_Character;

С := D: -- Ошибка, типы разные

Когда один тип получен из другого типа, называемого родительским (parent) типом, он наследует копию набора значений и копию набора операций, но ти­пы остаются разными. Однако всегда допустимо явное преобразование между типами, полученными друга из друга:

D := Derived_Character(C); -- Преобразование типов

С := Character(D); -- Преобразование типов

Можно даже задать другое представление для производного типа; преобразо­вание типов будет тогда преобразованием между двумя представлениями (см. раздел 5.8).

Производный тип может включать ограничение на диапазон значений родительского типа:

type Upper_Case is new Character range 'A'.. 'Z';

U: Upper_Case;

C: Character;

С := Character(U); -- Всегда правильно

U := Upper_Case(C); -- Может привести к ошибке

Производные типы в языке Ada 83 реализуют слабую версию наследования (weak version of inheritance), которая является центральным понятием объект­но-ориентированных языков (см. гл. 14). Пересмотренный язык Ada 95 реали­зует истинное наследование (true inheritance), расширяя понятие производ­ных типов; мы еще вернемся к их изучению.

Целочисленные типы

Предположим, что мы определили следующий тип:

type Altitudes is new Integer range 0 .. 60000;

Это определение работает правильно, когда мы программируем моделирова­ние полета на 32-разрядной рабочей станции. Что случается, когда мы пере­дадим программу на 16-разрядный контроллер, входящий в состав бортовой электроники нашего самолета? Шестнадцать битов могут представлять целые числа со знаком только до значения 32767. Таким образом, использование производного типа было бы ошибкой (так же, как подтипа или непосред­ственно Integer) и нарушило бы программную переносимость, которая явля­ется основной целью языка Ada.

Чтобы решать эту проблему, можно задать производный целый тип без яв­ного указания базового родительского типа:

type Altitudes is range 0 .. 60000;

Компилятор должен выбрать представление, которое соответствует требуемо­му диапазону — integer на 32-разрядном компьютере и Long_integer на 16-раз­рядном компьютере. Это уникальное свойство позволяет легко писать на языке Ada переносимые программы для компьютеров с различными длинами слова.

Недостаток целочисленных типов состоит в том, что каждое определение создает новый тип, и нельзя писать вычисления, которые используют разные типы без преобразования типа:

I: Integer;

A: Altitude;

А := I; -- Ошибка, разные типы

А := Altitude(l); -- Правильно, преобразование типов

Таким образом, существует неизбежный конфликт:

• Подтипы потенциально ненадежны из-за возможности писать смешан­ные выражения и из-за проблем с переносимостью.

• Производные типы безопасны и переносимы, но могут сделать програм­му трудной для чтения из-за многочисленных преобразований типов.