Книга: Основы объектно-ориентированного программирования
Конфликты при репликации: выделение
Конфликты при репликации: выделение
Рассмотрим теперь случай конфликтов переопределений, связанных с репликацией. Пусть при дублируемом наследовании происходит переопределение и переименование эффективного компонента, так что имеем два эффективных компонента, наделенных собственными именами.
Рис. 15.23. Необходимость выделения
Представленный на рисунке класс B меняет имя f на bf и переопределяет сам компонент. При этом мы опять полагаем, что C никак не меняет f, иное предположение нисколько не повлияет на ход нашего рассуждения. Более того, результат остался бы прежним, если бы B переопределял компонент f без его переименования, которое мы могли отложить до описания D. Допустим также, что речь не идет о соединении компонентов (которое происходит при переопределении обоих или отмене определения одного).
Поскольку компоненты наследуются под разными именами, то происходит их репликация. Класс D получает пару независимых компонентов, которые, в отличие от предыдущих случаев репликации, не являются копиями одного и того же компонента.
В отличие от случая совместного использования не возникает конфликта имен. Однако возникают другие конфликты, относящиеся к динамическому связыванию. Пусть полиморфная сущность a1 типа A (общий предок) на этапе выполнения связывается с экземпляром типа D (общим потомком). Что тогда означает вызов a1.f?
Правило динамического связывания гласит: вызываемый вариант f выбирается с учетом типа цели - объекта D. Но теперь это впервые нельзя истолковать однозначно: D содержит два равноценных варианта, известных под именами f и bf, соответствующих оригиналу f класса A.
Как и при конфликте имен, нельзя позволять компилятору делать выбор, пользуясь собственными правилами, - это противоречило бы принципам ясности и надежности. Управление ситуацией должно оставаться за автором разработки.
Для устранения неоднозначности необходим простой языковой механизм - предложение select. Вот версия класса, в которой предпочтение при динамическом связывании сущности f типа A отдается версии класса C:
class D inherit
C
select f end
feature
...
end
В этом варианте предпочтение отдается версии класса B:
class D inherit
select bf end
C
feature
...
end
Синтаксически предложение select следует за предложениями rename, undefine и redefine, если таковые имеются (выбор осуществляется после переименования и переопределения). Применение этого механизма регламентирует следующее правило:
Правило выделения
Класс, наследовавший две или более различные и эффективные версии компонента дублируемого предка и не переопределивший их, должен включить одну из них в предложение select.
Механизм select устраняет неоднозначность раз и навсегда. Потомкам класса нет необходимости (и они не должны) повторять выделение.
- Общие предки
- По обе стороны океана
- Совместное использование и репликация
- Ненавязчивое дублирующее наследование
- Правило переименования
- Конфликт переопределений
- Конфликт при совместном использовании: отмена определения и соединение компонентов
- Конфликты при репликации: выделение
- Выделение всех компонентов
- Сохранение исходной версии при переопределении
- Пример повышенной сложности
- Дублируемое наследование и универсальность
- Правила об именах
- 3.2.1.2. Начальное выделение памяти: malloc()
- Выделение огромных объемов памяти
- Выделение группы файлов
- Выделение ячеек
- Выделение памяти
- Простое выделение памяти
- Статическое выделение памяти в стеке
- 3.2. Выделение памяти
- 3.2.1.5. Выделение с инициализацией нулями: calloc()
- 14.1. Выделение выровненной памяти: posix_memalign() и memalign()
- Выделение фиксированных адресов
- Выделение дескриптора процесса