Правила об именах
Правила об именах
(В этом разделе мы только формализуем сказанное выше, поэтому при первом чтении книги его можно пропустить.)
Мы уже видели, что в случае возможной неоднозначности конфликты имен пресекаются, хотя некоторые ситуации бывают вполне корректны. Чтобы в представлении множественного и дублируемого наследования не оставить никакой неоднозначности, полезно обобщить ограничения на конфликт имен в едином правиле: Заканчивая этот раздел, сведем изложенный ранее материал в единое правило:
Конфликты имен: определение и правило
В классе, образованном в результате множественного наследования, возникает конфликт имен, если два компонента, наследованные от разных родителей, имеют одно и то же финальное имя.
Конфликт имен делает класс некорректным за исключением следующих случаев:
1 Оба компонента унаследованы от общего предка, и ни один из них не получен повторным объявлением версии предка.
2 Оба компонента имеют совместимые сигнатуры, и, по крайней мере, один из них наследуется в отложенной форме.
3 Оба компонента имеют совместимые сигнатуры и переопределяются в новом классе.
Ситуация (1) описывает совместное использование при дублируемом наследовании.
Для случая (2) "наследование в отложенной форме" возможно по двум причинам: либо отложенная форма задана родительским классом, либо компонент был эффективным, но порожденный класс отменил его реализацию (undefine).
Ситуации (2) и (3) рассматриваются отдельно, однако, их можно представить как один вариант - вариант соединения (join). Переходя к n компонентам (n >= 2), можно сказать, что ситуации (2) и (3) возникают, когда от разных родителей класс принимает n одноименных компонентов с совместимыми сигнатурами. Конфликт имен не делает класс некорректным, если эти компоненты могут быть соединены, иными словами:
[x]. все n компонентов отложены, так что некому вызвать конфликт определений;
[x]. существует единственный эффективный компонент. Его реализация станет реализацией остальных компонентов;
[x]. два или несколько компонентов эффективны. Класс должен их переопределить. Новая реализация будет использоваться как для переопределяемых компонентов, так и для любых отложенных компонентов, участвующих в конфликте.
И, наконец, точное правило употребления конструкции Precursor. Если в переопределении используется Precursor, то неоднозначность может возникнуть из-за того, что неясно, версию какого родителя следует вызывать. Чтобы решить эту проблему, следует использовать вызов вида Precursor {PARENT} (...), где PARENT - имя желаемого родителя. В остальных случаях указывать имя родителя не обязательно.