18.5.4. Видимость членов виртуального базового класса
18.5.4. Видимость членов виртуального базового класса
Изменим наш класс 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.
Когда два или более экземпляров члена наследуются разными путями (это относится не только к функциям-членам, но и к данным-членам, а также к вложенным типам) и все они представляют один и тот же член виртуального базового класса, неоднозначности не возникает, поскольку существует единственный разделяемый экземпляр (первая категория). Если один экземпляр представляет член виртуального базового, а другой – член унаследованного от него класса, то неоднозначности также не возникает: специализированному экземпляру из производного класса отдается предпочтение по сравнению с разделяемым экземпляром из виртуального базового (вторая категория). Но если оба экземпляра представляют члены производных классов, то прямое обращение неоднозначно. Лучше всего разрешить эту ситуацию, предоставив замещающий экземпляр в производном классе (третья категория).
Например, при невиртуальном наследовании неквалифицированное обращение к onExhibit() через объект Panda неоднозначно:
// ошибка: неоднозначно при невиртуальном наследовании
Panda yolo( "любитель бамбука" );
yolo.onExhibit();
В данном случае все унаследованные экземпляры имеют равные приоритеты при разрешении имени, поэтому неквалифицированное обращение приводит к ошибке компиляции из-за неоднозначности (см. раздел 18.4.1).
При виртуальном наследовании члену, унаследованному из виртуального базового класса, приписывается меньший приоритет, чем члену с тем же именем, замещенному в производном. Так, унаследованному от Bear экземпляру onExhibit() отдается предпочтение перед экземпляром из ZooAnimal, унаследованному через Raccoon:
// правильно: при виртуальном наследовании неоднозначности нет
// вызывается Bear::onExhibit()
yolo.onExhibit();
Если два или более классов на одном и том же уровне наследования замещают некоторый член виртуального базового, то в производном они будут иметь одинаковый вес. Например, если в Raccoon также определен член onExhibit(), то при обращении к нему из Panda придется квалифицировать имя с помощью оператора разрешения области видимости:
bool Panda::onExhibit()
{
return Bear::onExhibit() &&
Raccoon::onExhibit() &&
! _sleeping;
}
Упражнение 18.13
Дана иерархия классов:
class Class { ... };
class Base : public Class { ... };
class Derived1 : virtual public Base { ... };
class Derived2 : virtual public Base { ... };
class MI : public Derived1,
public Derived2 { ... };
class Final : public MI, public Class { ... };
(a)В каком порядке вызываются конструкторы и деструкторы при определении объекта Final?
(b)Сколько подобъектов класса Base содержит объект Final? А сколько подобъектов Class?
(c)Какие из следующих присваиваний вызывают ошибку компиляции?
Base *pb;
MI *pmi;
Class *pc;
Derived2 *pd2;
(i) pb = new Class; (iii) pmi = pb;
(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 { ... };
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
18.8.6 Доступ к дискам виртуального компьютера из ОС базового
18.8.6 Доступ к дискам виртуального компьютера из ОС базового Во всех трех рассмотренных примерах мы говорили только о том, как получить доступ к дискам базового компьютера из виртуального. Однако можно поставить вопрос и наоборот: как получить доступ к дискам виртуального
R.18.3.2 Старый стиль задания инициализатора базового класса
R.18.3.2 Старый стиль задания инициализатора базового класса В конструкции инициализатор-памяти (§R.12.6.2) можно не указывать имя-класса, обозначающее базовый класс при условии, что существует только один прямой (непосредственный) базовый класс. Поэтому в описанииclass B
8.10. Создание интерфейса с помощью абстрактного базового класса
8.10. Создание интерфейса с помощью абстрактного базового класса ПроблемаТребуется определить интерфейс, который будет реализовываться производными классами, но концепция этого интерфейса является абстракцией и не должна наследоваться сама по себе.РешениеСоздайте
Определение членов класса
Определение членов класса Все члены класса по характеру доступа к ним делятся на четыре категории: закрытые (private), защищенные (protected), открытые (public) и опубликованные (published).Элементы класса, определенные в разделе public, без каких-либо ограничений открыты для доступа извне
Роль базового класса WebService
Роль базового класса WebService В процессе разработки сервиса HelloWorldWebService вы имели возможность убедиться том, что Web-сервис можно получить непосредственно из System.Object. Но по умолчанию Web-сервисы, созданные в Visual Studio 2005, автоматически получаются из базового класса
17.2.1. Определение базового класса
17.2.1. Определение базового класса * Члены Query представляют: множество операций, поддерживаемых всеми производными от него классами запросов. Сюда входят как виртуальные операции, переопределяемые в производных классах, так и невиртуальные, разделяемые всеми производными
17.3. Доступ к членам базового класса
17.3. Доступ к членам базового класса Объект производного класса фактически построен из нескольких частей. Каждый базовый класс вносит свою долю в виде подобъекта, составленного из нестатических данных-членов этого класса. Объект производного класса построен из
17.4.1. Конструктор базового класса
17.4.1. Конструктор базового класса В нашем базовом классе объявлено два нестатических члена: _solution и _loc:class Query {public:// ...protected:setshort *_solution;vectorlocation _loc;// ...};Конструктор Query по умолчанию должен явно инициализировать только член _solution. Для инициализации _loc автоматически вызывается
18.5.1. Объявление виртуального базового класса
18.5.1. Объявление виртуального базового класса Для указания виртуального наследования в объявление базового класса вставляется модификатор virtual. Так, в данном примере ZooAnimal становится виртуальным базовым для Bear и Raccoon:// взаимное расположение ключевых слов public и virtual//
Разграничение доступа к элементам базового класса
Разграничение доступа к элементам базового класса Мы уже рассказывали, что можно управлять доступом к элементам класса, указывая спецификаторы доступа для элементов класса. Элементы класса, объявленные с спецификаторами protected и private доступны только из методов самого
Переопределение методов базового класса
Переопределение методов базового класса В порожденном классе можно определить методы и элементы данных с именами, которые уже используются в базовом классе. Соответствующие методы и элементы данных базового класса оказываются скрыты. Чтобы обратиться к ним, необходимо
Классы, не имеющие базового класса
Классы, не имеющие базового класса Кроме классов, наследованных от базового класса CObject, библиотека MFC включает ряд самостоятельных классов. У них нет общего базового класса и они имеют различное назначение.Несколько классов, которые не наследуются от базового класса
8.5.9 Видимость Имен Членов
8.5.9 Видимость Имен Членов Члены класса, описанные с ключевым словом class, являюся закрытыми, то есть, их имена могут использоваться только функциями членами (#8.5.2) и друзьями (см. #8.5.10), если они не стоят после метки «public:». В этом случае они являются открытыми. Открытый член
Видимость членов класса и модификаторы доступа
Видимость членов класса и модификаторы доступа Каждое поле, метод или свойство класса имеет модификатор (атрибут) доступа, задающий правила его видимости. В PascalABC.NET существуют четыре вида модификаторов доступа: public (открытый), private (закрытый), protected (защищенный) и internal