|
Программирование >> Разработка устойчивых систем
Проблемы разрешения имен Неоднозначности, рассмотренные нами для подобъектов, относятся к любым именам, в том числе к именам функций. Если класс имеет несколько непосредственных базовых классов с одноименными функциями, то при вызове одной из этих функций компилятор не будет знать, какую функцию выбрать. Рассмотрим пример подобной ощибки: C09:AmbiguousName.cpp {-хо} class Тор { public: virtual -TopO {} class Left : virtual public Top { public: void fO {} class Right : virtual public Top { public: void fO {} class Bottom : public Left, public Right {}: int mainO { Bottom b: b.fO: Ошибка } /:- Класс Bottom унаследовал две одноименные функции (сигнатура несущественна, поскольку разрещение имен происходит до разрещения перегрузки) и не может различить их. Стандартный способ ликвидации таких неоднозначностей основан на уточнении вызова функции именем базового класса: М in Е Е from G М in D D from F М in F F from G M in G G from main Инициализация g требует предварительной инициализации подобъектов Е и F, но сначала должны быть инициализированы подобъекты В и С, поскольку они относятся к виртуальным базовым классам и инициализируются по списку инициализации G, последнего производного класса в иерархии. Класс В не имеет базовых классов, поэтому по правилу 3 инициализируется его вложенный объект т, после чего конструктор выводит сообщение В from С; то же происходит с подобъектом С в Е. Подобъект Е требует инициализации подобъектов А, В и С. Поскольку подобъекты В и С уже были инициализированы, следующим инициализируется подобъект А подобъекта Е, а затем - сам подобъект Е. Далее сценарий повторяется для подобъекта F объекта д, но без дублирования инициализации виртуальных базовых классов. : С09:ВгеакТ1е.срр class Тор { public: virtual -TopO {} class Left : virtual public Top { public: void fO {} class Right : virtual public Top { public: void fO {} class Bottom : public Left, public Right { public: using Left::f: int mainO { Bottom b: b.fO: Вызов Left::f() } III:- Имя Left::f теперь находится в области видимости Bottom, поэтому имя Right::f вообше не рассматривается. Если потребуется ввести дополнительные возможности, выходящие за пределы Left::f(), вы реализуете функцию Bottom::f(), которая вызывает Left::f(). Между одноименными функциями в разных ветвях иерархии часто возникают конфликты. В следующей иерархии такой проблемы нет: : С09:Dominance.срр class Тор { public: virtual -TopO {} virtual void fO {} class Left : virtual public Top { public: void f(){} class Right : virtual public Top {}: class Bottom : public Left, public Right {}: int mainO { Bottom b: b.fO: Вызывает Left::f() } III:- B этой иерархии функции Right::f() нет. Для выражения b.f() будет выбрана функция Left::f(). Почему? Давайте представим, что класс Right не существует, то есть мы имеем дело с одиночным наследованием Тор <= Left <= Bottom. Конечно, в соответствии со стандартными правилами области видимости для выраже- Иерархия классов этого примера выглядит так: Обратите внимание: виртуальное наследование играет важную роль в этом примере. Если бы класс Тор не был виртуальным базовым классом, то в производный класс содержал бы несколько подобъектов Тор, и неоднозначность осталась бы. Доминирование при множественном наследовании действует только при наличии виртуальных базовых классов. ния b.f() будет вызвана функция Left.f(): производный класс рассматривается как находящийся во вложенной области видимости базового класса. В общем случае имя A::f доминирует над именем B::f, если А наследует от В, напрямую или косвенно, или другими словами, если А является более производным в иерархии, чем В. Выбирая между двумя одноименными функциями, компилятор выбирает доминирующее имя. Если такового не окажется, возникает неоднозначность. Следующая программа демонстрирует принцип доминирования: : C09:Dom1nance2.cpp #1 nclude <iostream> using namespace std: class A { public: virtual -AO {} virtual void f() {cout A::f\n :} class В : virtual public A { public: void fO {cout B::f\n :} class С : public В {}: class D : public C. virtual public A {}: int mainO { B* p = new D: p->f(): calls B::f() delete p: } /:-
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |