Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Область видимости класса при множественном наследовании
Как влияет множественное наследование на алгоритм просмотра области видимости класса? Все непосредственные базовые классы просматриваются одновременно, что может приводить к неоднозначности в случае, когда в нескольких из них есть одноименные члены. Рассмотрим на нескольких примерах, как возникает неоднозначность и какие меры можно предпринять для ее устранения. Предположим, есть следующий набор классов:
}; Panda объявляется производным от двух классов:
}; Хотя при наследовании функций print() и highlight() из обоих базовых классов Bear и Endangered имеется потенциальная неоднозначность, сообщение об ошибке не выдается до момента явно неоднозначного обращения к любой из этих функций. В то время как неоднозначность двух унаследованных функций print() очевидна с первого взгляда, наличие конфликта между членами highlight() удивляет (ради этого пример и составлялся): ведь у них разные уровни доступа и разные прототипы. Более того, экземпляр из Endangered – это член непосредственного базового класса, а из ZooAnimal – член класса, стоящего на две ступеньки выше в иерархии. Однако все это не имеет значения (впрочем, как мы скоро увидим, может иметь, но в случае виртуального наследования). Bear наследует закрытую функцию-член highlight() из ZooAnimal; лексически она видна, хотя вызывать ее из Bear или Panda запрещено. Значит, Panda наследует два лексически видимых члена с именем highlight, поэтому любое неквалифицированное обращение к этому имени приводит к ошибке компиляции. Поиск имени начинается в ближайшей области видимости, объемлющей его вхождение. Например, в коде
} ближайшей будет область видимости класса Panda, к которому принадлежит yin_yang. Если же мы напишем:
} то ближайшей будет локальная область видимости функции-члена mumble(). Если объявление dance в ней имеется, то разрешение имени на этом благополучно завершится. В противном случае поиск будет продолжен в объемлющих областях видимости. В случае множественного наследования имитируется одновременный просмотр всех поддеревьев наследования – в нашем случае это класс Endangered и поддерево Bear/ZooAnimal. Если объявление обнаружено только в поддереве одного из базовых классов, то разрешение имени заканчивается успешно, как, например, при таком вызове dance():
yin_yang.dance( Bear:: macarena ); Если же объявление найдено в двух или более поддеревьях, то обращение считается неоднозначным и компилятор выдает сообщение об ошибке. Так будет при неквалифицированном обращении к print():
} На уровне программы в целом для разрешения неоднозначности достаточно явно квалифицировать имя нужной функции-члена с помощью оператора разрешения области видимости:
} Предложенный способ неэффективен: теперь пользователь вынужден решать, каково правильное поведение класса Panda; однако лучше, если такого рода ответственность примет на себя проектировщик и класс Panda сам устранит все неоднозначности, свойственные его иерархии наследования. Простейший способ добиться этого – задать квалификацию уже в определении экземпляра в производном классе, указав тем самым требуемое поведение:
} Поскольку успешная компиляция производного класса, наследующего нескольким базовым, не гарантирует отсутствия скрытых неоднозначностей, мы рекомендуем при тестировании вызывать все функции-члены, даже самые тривиальные. Упражнение 18.9 Дана следующая иерархия классов:
}; и структура функции-члена MI:: foo():
} (a)Какие члены видны в классе MI? Есть ли среди них такие, которые видны в нескольких базовых? (b)Какие члены видны в MI:: foo()? Упражнение 18.10 Пользуясь иерархией классов из упражнения 18.9, укажите, какие из следующих присваиваний недопустимы внутри функции-члена MI:: bar():
(c) id = 1; Упражнение 18.11 Даны иерархия классов из упражнения 18.9 и скелет функции-члена MI:: foobar():
} (a)Присвойте локальной переменной dval сумму значений члена dval класса Base1 и члена dval класса Derived. (b)Присвойте вещественную часть члена cval класса MI члену fval класса Base2. (c)Присвойте значение члена cval класса Base1 первому символу члена sval класса Derived. Упражнение 18.12 Дана следующая иерархия классов, в которых имеются функции-члены print():
}; (a)Почему приведенный фрагмент дает ошибку компиляции?
mi.print( dancer ); (b)Как изменить определение MI, чтобы этот фрагмент компилировался и выполнялся правильно? |
Последнее изменение этой страницы: 2019-04-09; Просмотров: 414; Нарушение авторского права страницы