|
Программирование >> Инициализация объектов класса, структура
int dval; int Bear::mumble( int ival ) { foo( dval ); ... такой вызов: Если бы функция foo() была перегруженной, то перемещение члена ZooAnimal::dval из закрытой секции в защищенную вполне могло бы изменить всю последовательность вызовов внутри mumble() , а разработчик об этом даже и не подозревал бы. Если в базовом и производном классах есть функции-члены с одинаковыми именами и сигнатурами, то их поведение такое же, как и поведение данных-членов: член производного класса лексически скрывает в своей области видимости член базового. Для вызова члена базового класса необходимо применить оператор разрешения области ostreamS Bear::print( ostream Sos) const { вызается ZooA\nimal::print(os) ZooAnimal::print( os ); os << name; return os; видимости: 18.4.1. Область видимости класса при множественном наследовании Как влияет множественное наследование на алгоритм просмотра области видимости класса? Все непосредственные базовые классы просматриваются одновременно, что может приводить к неоднозначности в случае, когда в нескольких из них есть одноименные члены. Рассмотрим на нескольких примерах, как возникает неоднозначность и какие меры можно предпринять для ее устранения. Предположим, есть следующий набор классов: (c) Определено ли dval в области видимости ZooAnimal? Да. Обращение разрешается в пользу этого имени. После того как имя разрешено, компилятор проверяет, возможен ли доступ к нему. В данном случае нет: dval является закрытым членом, и прямое обращение к нему из mumble() запрещено. Правильное (и, возможно, имевшееся в виду) разрешение требует явного употребления оператора разрешения области видимости: return ival + ::dval; правильно Почему же имя члена разрешается перед проверкой уровня доступа? Чтобы предотвратить тонкие изменения семантики программы в связи с совершенно независимым, казалось бы, изменением уровня доступа к члену. Рассмотрим, например, class Endangered { public: ostreamS print( ostreamS ) const; void highlight(); ... class ZooAnimal { public: bool onExhibit() const; ... private: bool highlight( int zoo location ); ... class Bear : public ZooAnimal { public: ostreamS print( ostreamS ) const; void dance( dance type ) const; ... class Panda : public Bear, public Endangered { public: void cuddle() const; ... Panda объявляется производным от двух классов: }; Хотя при наследовании функций print() и highlight () из обоих базовых классов Bear и Endangered имеется потенциальная неоднозначность, сообщение об ошибке не выдается до момента явно неоднозначного обращения к любой из этих функций. В то время как неоднозначность двух унаследованных функций print() очевидна с первого взгляда, наличие конфликта между членами highlight() удивляет (ради этого пример и составлялся): ведь у них разные уровни доступа и разные прототипы. Более того, экземпляр из Endangered - это член непосредственного базового класса, а из ZooAnimal - член класса, стоящего на две ступеньки выше в иерархии. Однако все это не имеет значения (впрочем, как мы скоро увидим, может иметь, но в случае виртуального наследования). Bear наследует закрытую функцию-член highlight() из ZooAnimal; лексически она видна, хотя вызывать ее из Bear или Panda запрещено. Значит, Panda наследует два лексически видимых члена с именем highlight, поэтому любое неквалифицированное обращение к этому имени приводит к ошибке компиляции. Поиск имени начинается в ближайшей области видимости, объемлющей его вхождение. Например, в коде int main() Panda yin yang; yin yang.dance( Bear::macarena ); ближайшей будет область видимости класса Panda, к которому принадлежит yin yang. void Panda::mumble() dance( Bear::macarena ); ... Если же мы напишем: то ближайшей будет локальная область видимости функции-члена mumble() . Если объявление dance в ней имеется, то разрешение имени на этом благополучно завершится. В противном случае поиск будет продолжен в объемлющих областях видимости. В случае множественного наследования имитируется одновременный просмотр всех поддеревьев наследования - в нашем случае это класс Endangered и поддерево Bear/ZooAnimial. Если объявление обнаружено только в поддереве одного из базовых классов, то разрешение имени заканчивается успешно, как, например, при таком вызове правильно: Bear::dance() dance() : yin yang.dance( Bear::macarena ); Если же объявление найдено в двух или более поддеревьях, то обращение считается неоднозначным и компилятор выдает сообщение об ошибке. Так будет при int main() { ошибка: неоднозначность: одна из Bear::print( ostreamS ) const Endangered::print( ostreamS ) const Panda yin yang; yin yang.print( cout ); неквалифицированном обращении к print() : На уровне программы в целом для разрешения неоднозначности достаточно явно квалифицировать имя нужной функции-члена с помощью оператора разрешения области видимости:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |