В классе
Подобная неоднозначность недопустима. Отсюда правило:
Универсальность в правиле дублируемого наследования
Тип компонента, совместно используемого в правиле дублируемого наследования, а также тип любого из его аргументов не может быть родовым параметром класса, от которого произошло дублируемое наследование компонента.
Для устранения неоднозначности можно выполнить переименование в точке наследования.
Правила об именах
(В этом разделе мы только формализуем сказанное выше, поэтому при первом чтении книги его можно пропустить.)
Мы уже видели, что в случае возможной неоднозначности конфликты имен пресекаются, хотя некоторые ситуации бывают вполне корректны. Чтобы в представлении множественного и дублируемого наследования не оставить никакой неоднозначности, полезно обобщить ограничения на конфликт имен в едином правиле: Заканчивая этот раздел, сведем изложенный ранее материал в единое правило:
Конфликты имен: определение и правило
В классе, образованном в результате множественного наследования, возникает конфликт имен, если два компонента, наследованные от разных родителей, имеют одно и то же финальное имя.
Конфликт имен делает класс некорректным за исключением следующих случаев:
1 Оба компонента унаследованы от общего предка, и ни один из них не получен повторным объявлением версии предка.
2 Оба компонента имеют совместимые сигнатуры, и, по крайней мере, один из них наследуется в отложенной форме.
3 Оба компонента имеют совместимые сигнатуры и переопределяются в новом классе.
Ситуация (1) описывает совместное использование при дублируемом наследовании.
Для случая (2) 'наследование в отложенной форме' возможно по двум причинам: либо отложенная форма задана родительским классом, либо компонент был эффективным, но порожденный класс отменил его реализацию (undefine).
Ситуации (2) и (3) рассматриваются отдельно, однако, их можно представить как один вариант - вариант соединения (join). Переходя к
[x]. все
[x]. существует единственный эффективный компонент. Его реализация станет реализацией остальных компонентов;
[x]. два или несколько компонентов эффективны. Класс должен их переопределить. Новая реализация будет использоваться как для переопределяемых компонентов, так и для любых отложенных компонентов, участвующих в конфликте.
И, наконец, точное правило употребления конструкции
Обсуждение
Давайте проанализируем следствия некоторых решений, принятых в этой лекции.
Переименование
Любой язык, поддерживающий множественное наследование, должен как-то решать проблему конфликта имен. Коль скоро мы не можем и не должны требовать от разработчиков внесения изменений в исходные классы, есть всего два решения, помимо тех, что были описаны выше:
[x]. требовать от клиентов устранения всех неоднозначностей;
[x]. выбирать некую интерпретацию по умолчанию.
В соответствии с первым подходом, класс
x: C
... x.f ...
Клиенту придется квалифицировать ссылку на
Это решение противоречит, однако, одному из принципов, важность которого мы подчеркивали в этой лекции: структура наследования класса касается лишь самого класса и его предков, но не клиентов, за исключением случаев полиморфного применения компонентов. Пользуясь
Согласно второй стратегии, запись
Данный подход реализован в нескольких производных от Lisp языках с поддержкой множественного наследования. Тем не менее, выбор семантики по умолчанию весьма опасен ввиду потенциальной несовместимости со статической типизацией.
