Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции по основам ООП.docx
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
5.29 Mб
Скачать

И снова неограниченная универсальность

Конечно же, не все случаи универсальности ограничены. Форма - STACK [G] или ARRAY [G] - по-прежнему существует и называется неограниченной универсальностью. Пример DICTIONARY [G, H -> HASHABLE] показывает, что класс одновременно может иметь как ограниченные, так и неограниченные родовые параметры.

Изучение ограниченной универсальности дает шанс лучше понять неограниченный случай. Вы, конечно же, вывели правило, по которому class C [G] следует понимать как class C [G -> ANY] . Поэтому если G - неограниченный типовой параметр (например, класса STACK ), а x - сущность, имеющая тип G , то мы точно знаем, что можем делать с сущностью x : читать и присваивать значения, сравнивать (= , /= ), передавать как параметр и применять в универсальных операциях clone , equal и прочее.

Попытка присваивания

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

Когда правила типов становятся несносными

Цель правил типов, введенных вместе с наследованием, в достижении статически проверяемого динамического поведения, так чтобы система, прошедшая проверку при компиляции, не выполняла неадекватных операций над объектами во время выполнения.

Вот два основных правила, представленных в первой лекции о наследовании (лекция 14).

[x]. Правило Вызова Компонентов : запись x.f осмысленна лишь тогда, когда базовый класс x содержит и экспортирует компонент f .

[x]. Правило Совместимости Типов : при передаче a как аргумента или при присваивании его некой сущности необходимо, чтобы тип a был совместим с ожидаемым, то есть основан на классе, порожденным от класса сущности.

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

Правило Совместимости Типов требует больше внимания. Оно предполагает наличие у нас всей информации о типах объектов, с которыми мы работаем. Как правило, это так, - создав объекты, мы знаем, чем они являются, но иногда информация может частично отсутствовать. Вот два таких случая.

[x]. В полиморфной структуре данных мы располагаем лишь информацией, общей для всех объектов структуры; однако нам может понадобиться и специфическая информация, применимая только к отдельному объекту.

[x]. Если объект приходит из внешнего мира - файл или по сети - мы обычно не можем доверять тому, что он принадлежит определенному типу.

Давайте займемся исследованием примеров этих двух случаев. Рассмотрим для начала полиморфную структуру данных, такую как список геометрических фигур:

figlist: LIST [FIGURE]

В предыдущих лекциях рассматривалась иерархия наследования фигур. Пусть нам необходимо найти самую длинную диагональ среди всех прямоугольников списка (и вернуть -1, если прямоугольников нет). Сделать это непросто. Выражение item (i).diagonal , где item (i) - i -й элемент списка, идет вразрез с правилом вызова компонентов: item (i) имеет тип FIGURE , а этот класс, в отличие от его потомка RECTANGLE , не содержит в своем составе компонента diagonal . Решение, используемое до сих пор, изменяло определение класса, - в нем появлялся атрибут, задающий тип фигуры. Однако это решение не столь элегантно, как нам хотелось бы.

Теперь пример второго рассматриваемого случая. Пусть имеется механизм хранения объектов в файле или передачи их по сети, аналогичный универсальному классу STORABLE , описанному нами ранее. Для получения объекта используем:

my_last_book: BOOK

...

my_last_book := retrieved (my_book_file)

Значение, возвращаемое retrieved , имеет тип STORABLE библиотеки Kernel, хотя с тем же успехом оно может иметь тип ANY . Но мы не ожидали STORABLE или ANY , - мы надеялись получить именно BOOK . Присваивание my_last_book нарушает правило Совместимости Типов.

Даже если написать собственную функцию retrieved , учитывающую специфику приложения и объявленную с подходящим типом, вам не удастся полностью на нее положиться. В отличие от объектов вашего ПО, в котором согласованность типов гарантируется действующими правилами, данный объект к вам поступает со стороны. При его получении вы могли ошибиться в выборе имени файла и прочитать объект EMPLOYEE вместо объекта BOOK , файл мог быть подделан, а при сетевом доступе данные могли быть искажены при передаче.