Программирование >>  Разработка устойчивых систем 

1 ... 144 145 146 [ 147 ] 148 149 150 ... 196


Проблемы разрешения имен

Неоднозначности, рассмотренные нами для подобъектов, относятся к любым именам, в том числе к именам функций. Если класс имеет несколько непосредственных базовых классов с одноименными функциями, то при вызове одной из этих функций компилятор не будет знать, какую функцию выбрать. Рассмотрим пример подобной ощибки:

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: } /:-



1 ... 144 145 146 [ 147 ] 148 149 150 ... 196

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