Было бы ошибочно полагать, что проблема неоправданного переопределения возникает лишь там, где структура ориентирована на реализацию, как в LINKED_LIST. В любой схеме вида
some_attribute: SOME_TYPE set_attribute (a: SOME_TYPE) is do ... end
переопределение some_attribute подразумевает соответствующее переопределение set_attribute. В случае с put_right из BI_LINKABLE (не путайте с подпрограммой из LINKED_LIST) повторное определение необходимо, поскольку фактически меняется алгоритм. Но во многих широко распространенных случаях (к примеру, в set_alternate) новый алгоритм идентичен исходному.
Вот еще один пример, показывающий глубину проблемы (не ограниченной лишь процедурами set_xxx, которые сами появились в силу принципа Скрытия информации). Добавим в класс POINT функцию, которая возвращает точку, сопряженную с данной, - ее зеркальное отражение относительно горизонтальной оси:
conjugate: POINT is -- Точка, сопряженная с текущей do Result := clone (Current) -- Получить копию текущей точки Result.move (0, -2*y) -- Перенести результат по вертикали end
Рассмотрим теперь некий класс, порожденный от POINT, например PARTICLE. К атрибутам частиц, помимо координат, относятся, вероятно, масса и скорость. По идее, функция conjugate применима и к PARTICLE и выдает в результате ту же частицу с противоположным значением координаты y. Но если оставить все как есть, функция работать не будет из-за несоблюдения правила совместимости типов:
p1, p2: PARTICLE; create p1.make (...); ... p2 := p1.conjugate
Правая часть подчеркнутого оператора имеет тип POINT, левая часть - тип PARTICLE. Правило совместимости типов этого не допускает. Поэтому мы должны переписать conjugate для PARTICLE с единственной целью - обеспечить соблюдение правила.
Предприняв попытку присваивания, мы не решим проблему, а лишь запишем в p2 пустой указатель. |