Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP / books / Osnovi objektno-orientirovannogo programmirovaniya.pdf
Скачиваний:
62
Добавлен:
03.03.2016
Размер:
9.04 Mб
Скачать

Операции над ссылками

Мы уже знакомы с одним из способов изменения значения ссылки x: использование инструкции создания в форме create x, позволяющей создать новый объект и присоединить его к ссылке. Имеются и другие интересные операции, доступные при работе со ссылками.

Присоединение ссылки к объекту

Классы, появляющиеся в этой лекции, не имели подпрограмм - у них были только атрибуты. Как отмечалось, такие классы почти бесполезны, так как у них нет способа изменить значение атрибутов. Необходимы способы модификации ссылок, не использующие при этом инструкций в духе языков Pascal-C-Java-C++, подобных присваиванию: my_beloved.loved_one := me (напрямую изменяющих у объекта поле loved_one ), что нарушает принцип скрытия информации и синтаксически некорректно в нашей нотации.

Для модификации полей объекта клиент обязан вызвать подпрограмму, специально поставляемую разработчиком класса для этих целей. Давайте включим в класс PERSON1 процедуру, позволяющую модифицировать поле loved_one. Вот результат:

class PERSON2 feature name: STRING

loved_one, landlord: PERSON2 set_loved (l: PERSON2) is

-- Присоединить поле loved_one текущего объекта к объекту l. do

loved_one := l end

end

Процедура set_loved присваивает ссылочному полю loved_one текущего экземпляра PERSON2 значение другой ссылки l. Ссылочное присваивание (левая и правая части являются ссылками) присваивает значение источника (правой части) целевой ссылке (слева).

Эффект ссылочного присваивания очевиден: целевая ссылка становится присоединенной к объекту, к которому присоединен источник - или становится void, если такое значение имеет источник. Предположим, например, что мы начинаем с ситуации, изображенной на рис.8.12 , где поля landlord и loved_one всех изображенных объектов пока пусты.

Рис. 8.12. Перед присваиванием ссылке Предположим, что выполняется вызов процедуры:

a.set_loved (r)

Сущность a присоединена к объекту O1, а сущность r - к O3. В результате выполнения процедуры set_loved выполнится присваивание:

loved_one := l

Здесь в роли текущего объекта выступает объект O1, сущности l и r имеют одинаковое значение - ссылки на объект O3. В результате изменится значение поля loved_one объекта O1 - ссылка присоединится к другому объекту O3, как показано на следующем рисунке:

Если бы r было пустой ссылкой, то такой же в результате присваивания стала бы и ссылка в поле loved_one объекта O1.

Рис. 8.13. После присваивания ссылки

Сравнение ссылок

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

Если x и y - сущности ссылочного типа, то выражение:

x = y

истинно тогда и только тогда, когда обе ссылки пусты или присоединены к одному и тому же объекту. Противоположный оператор "не эквивалентно" записывается как /=.

Выражение:

r = a.loved_one

истинно в ситуации, представленной на рис.8.13 и ложно для ситуации рис.8.12 .

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

Значение void

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

Void

играет эту роль.

Обычно компонент Void используется в тестах, проверяющих пустоту ссылок:

if x = Void then ...

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

x := Void

В результате последнего присваивания происходит отсоединение ссылки от объекта, и она становится пустой. Эта ситуация показана на следующем рисунке:

Рис. 8.14. Отсоединение ссылки от объекта

|Присваивание Void ссылке не оказывает никакого влияния на объект, ранее присоединенный к ссылке, - разрывается только связь между ссылкой и объектом. Было бы некорректно рассматривать эту операцию как освобождение памяти, так как другие ссылки могут продолжать быть связанными с объектом (на рисунке x может быть отсоединено от объекта O1, но другие ссылки могут быть еще присоединены к нему). Об управлении памятью смотри следующую лекцию. |

Клонирование и сравнение объектов

Ссылочное присваивание приводит к тому, что две или несколько ссылок присоединяются к одному объекту. Иногда необходима другая форма присваивания, в результате которой мы хотим получить не копию ссылки, а копию объекта. Эта цель достигается при вызове функции клонирования clone.

Если y присоединено к объекту OY, выражение

clone (y)

означает создание нового объекта OX, такого, что он имеет те же поля, что и OY, и все соответствующие поля имеют идентичные значения. Если y равно void, то значение clone (y) также void.

Скопировать присоединенный к y объект и связать копию со ссылкой x позволяет присваивание:

[1]

x := clone (y)

Вот иллюстрация этого механизма:

Рис. 8.15. Клонирование объекта Наряду со сравнением ссылок необходим механизм, позволяющий сравнивать объекты.

Этой цели служит функция equal. Вызов:

equal (x, y)

возвращает значение true, если и только если x и y оба имеют значение void или присоединены к двум объектам с идентичными полями. После выполнения присваивания с клонированием [1], состояние, непосредственно следующее за присваиванием, удовлетворяет equal (x, y).

|Возможно, вы удивляетесь, почему у функции clone есть аргумент, а у функции equal - их два. Для ОО-стиля характерен квалифицируемый вызов в форме: y.twin и x.is_equal (y). Ответ появится в разделе обсуждения, но это будет еще не скоро, так что попытайтесь догадаться сами.

|

Соседние файлы в папке books