Согласованность типов

Наследование согласовано с системой типов. Основные правила легко объяснить на приведенном выше примере. Предположим, что имеются следующие объявления:

p: POLYGON

r: RECTANGLE

Выделим в приведенной выше иерархии нужный фрагмент (рис. 14.6).

Тогда законны следующие выражения:

[x]. p.perimeter: никаких проблем, поскольку perimeter определен для многоугольников;

[x]. p.vertices, p.translate (...), p.rotate (...) с корректными аргументами;

[x]. r.diagonal, r.side1, r.side2: эти три компонента объявлены на уровне RECTANGLE или QUADRANGLE;

[x]. r.vertices, r.translate (...), r.rotate (...): эти компоненты объявлены на уровне POLYGON или еще выше и поэтому применимы к прямоугольникам, наследующим все компоненты многоугольников;

[x]. r.perimeter: то же, что и в предыдущем случае. Но у вызываемой здесь функции имеется новое определение в классе RECTANGLE, так что она отличается от функции с тем же именем из класса POLYGON.

Рис. 14.6.  Фрагмент иерархии геометрических фигур

А следующие вызовы компонентов незаконны, так как эти компоненты недоступны на уровне многоугольника:

p.side1

p.side2

p.diagonal

Это рассмотрение основано на первом фундаментальном правиле типизации:

Правило Вызова Компонентов

Если тип сущности x основан на классе С, то в вызове компонента x.f сам компонент f должен быть определен в одном из предков С.

Напомним, что класс С является собственным предком. Фраза 'тип сущности x основан на классе С' напоминает, что для классов, порожденных из родовых, тип может включать не только имя класса: LINKED_LIST [INTEGER] . Но базовый класс для типа - это LINKED_LIST, так что родовой параметр никак не участвует в нашем правиле.

Как и все другие правила корректности, рассматриваемые в этой книге, правило Вызова Компонентов является статическим, - его можно проверять на основе текста системы, а не по ходу ее выполнения. Компилятор (который, как правило, выполняет такую проверку) будет отвергать классы, содержащие некорректные вызовы компонентов. Если успешно реализовать проверку правил типизации, то не возникнет риск того, что скомпилированная система когда-либо во время выполнения применит некоторый компонент к объекту неподходящего типа.

Статическая типизация - это один из главных ресурсов ОО-технологии для достижения объявленной в 1-ой лекции цели - надежности ПО.

Уже отмечалось, что не все подходы к построению ОО-ПО имеют статическую типизацию. Наиболее известным представителем языков с динамической типизацией является Smalltalk, в котором не действует статическое правило вызова, но допускается, чтобы вычисление аварийно завершалось в случае возникновения ошибки: 'сообщение не понятно'. В лекции, посвященной типизации, будет приведено сравнение разных подходов.

Пределы полиморфизма

Неограниченный полиморфизм был бы несовместим со статическим понятием типа. Допустимость полиморфных операций определяется наследственностью.

Все примеры полиморфных присваиваний, такие, как p := r и p := t, в качестве типа источника используют потомков класса-цели. Скажем, что в таком случае тип источника согласован с классом цели. Например, SQUARE согласован с RECTANGLE и с POLYGON, но не с TRIANGLE. Чтобы уточнить это понятие, дадим формальное определение:

Определение: согласованность

Тип U согласован с типом T, только если базовый класс для U является потомком базового класса для T; при этом для универсально порожденных типов каждый фактический параметр U должен (по рекурсии) быть согласован с соответствующим формальным параметром T.

Почему недостаточно понятия потомка в этом определении? Причина снова в том, что допускается порождение из родовых классов, поэтому приходится различать типы и классы. Для каждого типа имеется базовый класс, который при отсутствии порождения совпадает с самим типом (например, POLYGON является базовым для себя). При этом для универсально порожденного класса базовым является универсальный класс с опущенными родовыми параметрами. Например, для класса LIST [POLYGON] базовым будет класс LIST. Вторая часть определения говорит о том, что B [Y] будет согласован с A [X] , если B является потомком A, а Y - потомком X.

Заметим, что поскольку каждый класс является собственным потомком, то каждый тип согласован сам с собой.

При таком обобщении понятия потомка получаем второе важное правило типизации:

Правило согласования типов

Присоединение к источнику y цели x (т. е. присваивание x:=y или использование y в качестве

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату