Язык программирования C++. Вводный курс

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


Изменим наш класс Bear

так, чтобы он имел собственную реализацию функции-члена onExhibit(), предоставляемой также ZooAnimal:

bool Bear::onExhibit() { ... }

Теперь обращение к onExhibit()

через объект Bear

разрешается в пользу экземпляра, определенного в этом классе:

Bear winnie( "любитель меда" );

winnie.onExhibit();       // Bear::onExhibit()



Обращение же к onExhibit()

через объект Raccoon

разрешается в пользу функции-члена, унаследованной из ZooAnimal:

Raccoon meeko( "любитель всякой еды" );

meeko.onExhibit();       // ZooAnimal::onExhibit()

Производный класс Panda

наследует члены своих базовых классов. Их можно отнести к одной из трех категорий:

·         члены виртуального базового класса ZooAnimal, такие, как name() и family(), не замещенные ни в Bear, ни в Raccoon;

·         член onExhibit()

виртуального базового класса ZooAnimal, наследуемый при обращении через Raccoon и замещенный в классе Bear;

·         специализированные в классах Bear и Raccoon

экземпляры функции print() из ZooAnimal.

Можно ли, не опасаясь неоднозначности, напрямую обращаться к унаследованным членам из области видимости класса Panda? В случае невиртуального наследования – нет: все неквалифицированные ссылки на имя неоднозначны. Что касается виртуального наследования, то прямое обращение допустимо к любым членам из первой и второй категорий. Например, дан объект класса Panda:

Panda spot( "Spottie" );

Тогда инструкция

spot.name();

вызывает разделяемую функцию-член name()

виртуального базового ZooAnimal, а инструкция

spot.onExhibit();

вызывает функцию-член onExhibit()

производного класса Bear.

Когда два или более экземпляров члена наследуются разными путями (это относится не только к функциям-членам, но и к данным-членам, а также к вложенным типам) и все они представляют один и тот же член виртуального базового класса, неоднозначности не возникает, поскольку существует единственный разделяемый экземпляр (первая категория). Если один экземпляр представляет член виртуального базового, а другой – член унаследованного от него класса, то неоднозначности также не возникает: специализированному экземпляру из производного класса отдается предпочтение по сравнению с разделяемым экземпляром из виртуального базового (вторая категория). Но если оба экземпляра представляют члены производных классов, то прямое обращение неоднозначно. Лучше всего разрешить эту ситуацию, предоставив замещающий экземпляр в производном классе (третья категория).


(ii) pc = new Final;   (iv)  pd2 = pmi;

Упражнение 18.14

Дана иерархия классов:



class Base {

public:

   bar( int );

   // ...

protected:

   int ival;

   // ...

};

class Derived1 : virtual public Base {

public:

   bar( char );

   foo( char );

   // ...

protected:

   char cval;

   // ...

};

class Derived2 : virtual public Base {

public:

   foo( int );

   // ...

protected:

   int ival;

   char cval;

   // ...

};

class VMI : public Derived1, public Derived2 {};

К каким из унаследованных членов можно обращаться из класса VMI, не квалифицируя имя? А какие требуют квалификации?

Упражнение 18.15

Дан класс Base с тремя конструкторами:



class Base {

public:

   Base();

   Base( string );

   Base( const Base& );

   // ...

protected:

   string _name;
};

Определите соответствующие конструкторы для каждого из следующих классов:



(a) любой из

    class Derived1 : virtual public Vase { ... };

    class Derived2 : virtual public Vase { ... };

(b) class VMI : public Derived1, public Derived2 { ... };
(c) class Final : public VMI { ... };


Содержание раздела