Программирование >>  Инициализация объектов класса, структура 

1 ... 313 314 315 [ 316 ] 317 318 319 ... 395


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() :

На уровне программы в целом для разрешения неоднозначности достаточно явно квалифицировать имя нужной функции-члена с помощью оператора разрешения области видимости:



1 ... 313 314 315 [ 316 ] 317 318 319 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика