cout << ying_yang;  // ok: передает объект Panda как ZooAnimal

Видимость членов виртуальных базовых классов

Поскольку виртуальному базовому классу соответствует только один совместно используемый внутренний объект, к членам объекта этого базового класса можно обратиться непосредственно и однозначно. Кроме того, если член виртуального базового класса переопределяется только в одной ветви наследования, к этому переопределенному члену класса можно обратиться непосредственно. Если член переопределяется больше чем одним базовым классом, то производный класс вообще должен определить собственную версию этого члена.

Предположим, например, что класс В определяет члены по имени x; класс D1 виртуально наследует класс В, как и класс D2; а класс D происходит от классов D1 и D2. Из области видимости класса D член x видим через оба своих базовых класса. Есть три возможности использовать член x через объект класса D:

• Если член x не будет определен ни в классе D1, ни в D2, то будет использован член класса В; никакой неоднозначности нет. Объект класса D содержит только один экземпляр члена x.

• Если x является членом класса В и одного (но не обоих) из классов D1 или D2, никакой неоднозначности снова нет: версия в производном классе имеет приоритет перед совместно используемым виртуальным базовым классом B.

• Если член x определяется и в классе D1, и в классе D2, то прямой доступ к этому члену неоднозначен.

Как и в иерархии с невиртуальным множественным наследованием, подобная неоднозначность лучше всего устраняется переопределением члена в производном классе.

Упражнения раздела 18.3.4

Упражнение 18.28. Рассмотрим следующую иерархию класса. Можно ли в классе vmi обращаться к унаследованным членам без уточнения? Какие из них требуют полностью квалифицированных имен? Объясните, почему.

struct Base {

 void bar(int); // по умолчанию открыты

protected:

 int ival;

};

struct Derived1 : virtual public Base {

 void bar(char); // по умолчанию открыты

 void foo(char);

protected:

 char cval;

};

struct Derived2 : virtual public Base {

 void foo(int); // по умолчанию открыты

protected:

 int ival;

 char cval;

};

class VMI : public Derived1, public Derived2 { };

<p>18.3.5. Конструкторы и виртуальное наследование</p>

При виртуальном наследовании виртуальный базовый класс инициализируется конструктором самого последнего производного класса. В рассматриваемом примере при создании объекта класса Panda инициализацию членов базового класса ZooAnimal контролирует конструктор класса Panda.

Чтобы понять это правило, рассмотрим происходящее при применении обычных правил инициализации. В этом случае объект виртуального базового класса мог бы быть инициализирован несколько раз. Он был бы инициализирован вдоль каждой ветви наследования, содержащей этот виртуальный базовый класс. В данном примере, если бы к классу ZooAnimal применялись обычные правила инициализации, то части Bear и Raccoon инициализировали бы часть ZooAnimal объекта класса Panda.

Конечно, каждый базовый класс в иерархии объекта мог бы в некоторый момент быть "более производным". Поскольку вполне можно создавать независимые объекты класса, производного от виртуального базового класса, конструкторы в этом классе должны инициализировать его виртуальный базовый класс. Например, когда в рассматриваемой иерархии создается объект класса Bear (или Raccoon), никакого дальнейшего применения производного класса нет. В данном случае конструкторы класса Bear (или Raccoon) непосредственно инициализируют базовую часть ZooAnimal, как обычно:

Bear::Bear(std::string name, bool onExhibit) :

 ZooAnimal(name, onExhibit, "Bear") { }

Raccoon::Raccoon(std::string name, bool onExhibit) :

 ZooAnimal(name, onExhibit, "Raccoon") { }

Когда создается объект класса Panda, он является наиболее производным типом и контролирует инициализацию совместно используемого базового класса ZooAnimal. Даже при том, что класс ZooAnimal не является прямым базовым классом для класса Panda, часть ZooAnimal инициализирует конструктор класса Panda:

Panda::Panda(std::string name, bool onExhibit)

 : ZooAnimal(name, onExhibit, "Panda"),

   Bear(name, onExhibit),

   Raccoon(name, onExhibit),

Перейти на страницу:

Похожие книги