18.5.1. Объявление виртуального базового класса
18.5.1. Объявление виртуального базового класса
Для указания виртуального наследования в объявление базового класса вставляется модификатор virtual. Так, в данном примере ZooAnimal становится виртуальным базовым для Bear и Raccoon:
// взаимное расположение ключевых слов public и virtual
// несущественно
class Bear : public virtual ZooAnimal { ... };
class Raccoon : virtual public ZooAnimal { ... };
Виртуальное наследование не является явной характеристикой самого базового класса, а лишь описывает его отношение к производному. Как мы уже отмечали, виртуальное наследование – это разновидность композиции по ссылке. Иначе говоря, доступ к подобъекту и его нестатическим членам косвенный, что обеспечивает гибкость, необходимую для объединения нескольких виртуально унаследованных подобъектов базовых классов в один разделяемый экземпляр внутри производного. В то же время объектом производного класса можно манипулировать через указатель или ссылку на тип базового, хотя последний является виртуальным. Например, все показанные ниже преобразования базовых классов Panda выполняются корректно, хотя Panda использует виртуальное наследование:
extern void dance( const Bear* );
extern void rummage( const Raccoon* );
extern ostream&
operator( ostream&, const ZooAnimal& );
int main()
{
Panda yin_yang;
dance( &yin_yang ); // правильно
rummage( &yin_yang ); // правильно
cout yin_yang; // правильно
// ...
}
Любой класс, который можно задать в качестве базового, разрешается сделать виртуальным, причем он способен содержать все те же элементы, что обычные базовые классы. Так выглядит объявление ZooAnimal:
#include iostream
#include string
class ZooAnimal;
extern ostream&
operator( ostream&, const ZooAnimal& );
class ZooAnimal {
public:
ZooAnimal( string name,
bool onExhibit, string fam_name )
: _name( name ),
_onExhibit( onExhibit ), _fam_name( fam_name )
{}
virtual ~ZooAnimal();
virtual ostream& print( ostream& ) const;
string name() const { return _name; }
string family_name() const { return _fam_name; }
// ...
protected:
bool _onExhibit;
string _name;
string _fam_name;
// ...
};
К объявлению и реализации непосредственного базового класса при использовании виртуального наследования добавляется ключевое слово virtual. Вот, например, объявление нашего класса Bear:
class Bear : public virtual ZooAnimal {
public:
enum DanceType {
two_left_feet, macarena, fandango, waltz };
Bear( string name, bool onExhibit=true )
: ZooAnimal( name, onExhibit, "Bear" ),
_dance( two_left_feet )
{}
virtual ostream& print( ostream& ) const;
void dance( DanceType );
// ...
protected:
DanceType _dance;
// ...
};
А вот объявление класса Raccoon:
class Raccoon : public virtual ZooAnimal {
public:
Raccoon( string name, bool onExhibit=true )
: ZooAnimal( name, onExhibit, "Raccoon" ),
_pettable( false )
{}
virtual ostream& print( ostream& ) const;
bool pettable() const { return _pettable; }
void pettable( bool petval ) { _pettable = petval; }
// ...
protected:
bool _pettable;
// ...
};
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
18.8.6 Доступ к дискам виртуального компьютера из ОС базового
18.8.6 Доступ к дискам виртуального компьютера из ОС базового Во всех трех рассмотренных примерах мы говорили только о том, как получить доступ к дискам базового компьютера из виртуального. Однако можно поставить вопрос и наоборот: как получить доступ к дискам виртуального
R.18.3.2 Старый стиль задания инициализатора базового класса
R.18.3.2 Старый стиль задания инициализатора базового класса В конструкции инициализатор-памяти (§R.12.6.2) можно не указывать имя-класса, обозначающее базовый класс при условии, что существует только один прямой (непосредственный) базовый класс. Поэтому в описанииclass B
Объявление переменных класса
Объявление переменных класса Для объявления переменных, которые понадобятся в нескольких свойствах или методах, используйте раздел Declarations в самом начале модуля класса. Всегда объявляйте эти переменные как локальные ( Private ), ведь объекты в основном предназначены для
8.10. Создание интерфейса с помощью абстрактного базового класса
8.10. Создание интерфейса с помощью абстрактного базового класса ПроблемаТребуется определить интерфейс, который будет реализовываться производными классами, но концепция этого интерфейса является абстракцией и не должна наследоваться сама по себе.РешениеСоздайте
Роль базового класса WebService
Роль базового класса WebService В процессе разработки сервиса HelloWorldWebService вы имели возможность убедиться том, что Web-сервис можно получить непосредственно из System.Object. Но по умолчанию Web-сервисы, созданные в Visual Studio 2005, автоматически получаются из базового класса
13.1.5. Объявление и определение класса
13.1.5. Объявление и определение класса О классе говорят, что он определен, как только встретилась скобка, закрывающая его тело. После этого становятся известными все члены класса, а следовательно, и его размер.Можно объявить класс, не определяя его. Например:class Screen; //
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.4. Видимость членов виртуального базового класса
18.5.4. Видимость членов виртуального базового класса Изменим наш класс Bear так, чтобы он имел собственную реализацию функции-члена onExhibit(), предоставляемой также ZooAnimal: bool Bear::onExhibit() { ... }Теперь обращение к onExhibit() через объект Bear разрешается в пользу экземпляра, определенного в
Разграничение доступа к элементам базового класса
Разграничение доступа к элементам базового класса Мы уже рассказывали, что можно управлять доступом к элементам класса, указывая спецификаторы доступа для элементов класса. Элементы класса, объявленные с спецификаторами protected и private доступны только из методов самого
Переопределение методов базового класса
Переопределение методов базового класса В порожденном классе можно определить методы и элементы данных с именами, которые уже используются в базовом классе. Соответствующие методы и элементы данных базового класса оказываются скрыты. Чтобы обратиться к ним, необходимо
Классы, не имеющие базового класса
Классы, не имеющие базового класса Кроме классов, наследованных от базового класса CObject, библиотека MFC включает ряд самостоятельных классов. У них нет общего базового класса и они имеют различное назначение.Несколько классов, которые не наследуются от базового класса
Объявление родового класса
Объявление родового класса По соглашению родовой параметр обычно, использует имя G (от Generic). Это неформальное правило. Если нужны еще родовые параметры, они будут названы H, I и т.д.Согласно синтаксису, формальные родовые параметры заключаются в квадратные скобки,