Опубликован: 03.10.2011 | Уровень: для всех | Доступ: свободно
Лекция 7:

Создание объектов и выполняемых систем

6.3. VOID-ссылки

При рассмотрении выполнения build_a_line и значения fancy_line особое внимание следует обратить на ссылки и их связи с объектами.

Начальное состояние ссылки

Предположим, что у нас есть экземпляр класса LINE_BUILDING. Возможно, вы думаете, что поскольку класс объявил запрос fancy_line типа LINE, отсюда всегда следует, что этот экземпляр содержит ссылку на экземпляр LINE, как показано на рисунке:

 Объекты LINE_BUILDING и LINE

Рис. 6.3. Объекты LINE_BUILDING и LINE

Это не так. У нас есть объект, показанный слева на рисунке, — экземпляр LINE_BUILDING, с одним полем, соответствующим запросу fancy_line. Давайте предположим, что это объект уже создан в результате вызова "оператора создания", который мы вскоре научимся писать. Этот оператор даст нам только один объект: LINE_BUILDING. Если нам нужен другой объект, то он должен быть явно создан в программе, потому состояние программы сразу после создания экземпляра LINE_BUILDING выглядит так:

 Структура объекта в начале выполнения

Рис. 6.4. Структура объекта в начале выполнения

Поле fancy_line содержит ссылку. Но поскольку все же нет оператора, создающего другие объекты, ссылка имеет значение void, означающее, что она не присоединена ни к какому объекту. Рисунок отражает принятое соглашение для изображения void-ссылок, напоминая "заземление" в электрических цепях.

Ссылка может находиться в одном из двух возможных состояний.

Определение: состояния ссылкa
В любой момент выполнения значение сущности, обозначающее ссылку, может быть:
  • присоединенным к некоторому объекту;
  • void.

Предопределенный компонент Void обозначает ссылку. Так что в любой момент выполнения, если x обозначает ссылку, условие

x = Void

имеет значение True, если и только если значение x является void-ссылкой; и

x /= Void

если и только если сущность x присоединена к объекту.

Трудности с void-ссылками

Базисный механизм вычисления был представлен как вызов метода в форме x.f или с аргументами x.f (...). Метод применяется к объекту, к которому x присоединен. Но теперь, при наличии ссылок, возникает возможность, что в некоторый момент выполнения, если верно x = Void, ссылка, которую обозначает x, не присоединена ни к какому объекту. Вызов метода в этом случае будет ошибочным.

Чтобы увидеть эффект от такого "жучка", попытаемся выполнить систему в следующей форме:

class LINE_BUILDING inherit
    TOURISM
feature
      build_a_line
        — Построить воображаемую линию и подсветить ее на карте.
      do
        Paris .display
      — Paris .put_line (fancy_line)
          — Следующая строка должна быть заменена кодом!
        — "Создать fancy_line и подсветить ее на карте"
        fancy_line .highlight
      end
    fancy_line: LINE
end

Как показано, следует временно закомментировать строку Paris.put_line (fancy_line). Эта строка сама по себе содержит ошибку, но нас сейчас интересует другая ошибка.

После начального вызова (Paris.display) выполнение будет прервано, и появится сообщение, указывающее, что встретилось исключение.

 Завершение по прерыванию

увеличить изображение
Рис. 6.5. Завершение по прерыванию

То, что случилось, является void-вызовом, или попыткой вызова метода void-целью, — вызовом метода несуществующим объектом. Такая попытка никогда не может быть успешной.

Почувствуй Семантику: Принцип присоединенной цели
Вызов в форме x.f (...) может выполняться нужным образом только при условии, что в момент его выполнения x является присоединенным.

При void-вызове возникает исключение: событие, вызывающее прерывание нормального процесса выполнения программы. В данном случае исключение привело к отказу выполнения всей программы. Сообщение EiffelStudio указывает имя происшедшего исключения: "Feature call on void reference" (вызов метода void-ссылкой).

Изучая исключения, мы увидим, что можно избежать отказа, подготовив код обработки исключения, который будет пытаться восстановить ситуацию. Но это приемы "последней надежды". Предотвратить — лучше, чем лечить. Общее правило: всякий раз, когда в программе встречается вызов x.f (...), при котором возможно, что x может быть void, защитите вызов, чтобы он мог выполняться только тогда, когда x присоединен. Примером является библиотечный код, где можно увидеть много проверок вида if x /= Void then ... и предусловий в форме x /= Void, когда x — это аргумент вызова. Вы должны проследить, чтобы цели всех вызовов были присоединенными при каждом выполнении.

Ситуация улучшается. Приложение к этой лекции описывает современную эволюцию, при которой полностью исключается риск void-вызовов.

Если раскомментировать строку Paris.put_line (fancy_line), перекомпилировать и выполнить программу, то произойдет отказ в работе, но по другой причине — нарушено предусловие метода put_line, которое устанавливает, что аргумент не должен быть void (причина того, что эту строку следовало вначале закомментировать, состояла в том, что хотелось вначале познакомиться с ситуацией void-вызова).

Кирилл Юлаев
Кирилл Юлаев
Как происходит отслеживание свободного экстента?
Федор Антонов
Федор Антонов
Оплата и обучение
Наталья Алмаева
Наталья Алмаева
Россия
Андрей Лучицкий
Андрей Лучицкий
Россия