Видимость членов виртуального базового класса
Изменим наш класс 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; // ... }; |
К каким из унаследованных членов можно обращаться из класса 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 { ... }; |