Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
samples / Zaochniki / ООП.doc
Скачиваний:
28
Добавлен:
25.03.2015
Размер:
183.81 Кб
Скачать

№10 Использование виртуальных базовых классов

Виртуальные базовые классы используются только при множественном наследовании. Из-за сложности вза­имосвязей, возникающих в дереве наследования, построенном на основе множественного наследования, возникают ситуации, когда программисту нужен определенный контроль над тем, как наследуются базовые классы. Рассмот­рим дерево наследования, представленное на рис. 10.1.

Класс А является базовым для класса D. Проблема в том, что здесь два одинаковых класса А, которые являются базовыми для D, со своими собственными данными. В реальной жизни это подобно наличию у вас двух дедушек, которые не только близнецы, но и имеют одинаковые имена! Как быть? Рассмотрим следующий код:

class A { public;

Int value;

};

class В: public A { };

class C: public A { };

class D: public B, public С {

public:

int Value( ) { return value; } };

Рис. 10.1. Дерево наследования с классом, появляющимся дважды

Оператор доступа к члену данных value в D неоднозначен. Borland C++ сгенерирует ошибку:

(Поле 'value' является двусмысленным в функции D : : Valued)

Компилятор не понимает, на какую копию value ссылаться. Для устранения неоднозначности следует в функ­ции D : : Value () применить оператор разрешения видимости: int Valued { return С : : value; }

Как показано в листинге 10.2, функция вне класса D также могла бы получить доступ к каждому value, используя, оператор разрешения видимости в сочетании с идентификатором объекта.

Листинг' 10.2. Использование оператора разрешения видимости в классе с несколь­кими базовыми классами

void main( )

{

D d;

int v = d.B : : value; // с объектом

D* object = new D;

int w = object->B : : value; // с указателем на объект

};

Наличие в дереве наследования нескольких копий одного и того же базового класса не только вносит путаницу, но и приводит к излишним затратам памяти. Объявление базового класса виртуальным решает эту проблему. По­добное объявление заставляет компилятор принимать только одну копию данного базового класса в объявлении производного класса. Тогда класс D можно определить следующим образом:

class В: public virtual A { };

class С: public virtual A { };

class D: public B, public С {

public:

int Valued { return value; }

};

Порядок ключевых слов public и virtual не имеет никакого значения. Дерево на­следования, описываемое этим кодом, будет выглядеть так, как показано на рис. 10.3.

Код функции D:: Value () больше не нуждается в операторе разрешения видимости, хотя его использование не является ошибкой.

Рис. 10.3. Дерево наследования с классом, появляющимся дважды

Использование виртуальных и невиртуальных базовых классов вместе

Класс допускает существование как виртуальных, так и невиртуальных базовых классов. Они могут объявлять­ся в любом порядке и в любой комбинации. Взаимосвязи между классами лучше видны из дерева наследования, представленного на рис. 10.4. Класс E наследует две разные копии класса А. Для компилятора C++ это не является ошибкой, но для пользователей может оказаться слишком слож­ным. Порядок вызова конструкторов для класса Е таков: А, В, С, D, E. Преж­де всего, строятся виртуальные базы, а затем — все остальные. Порядок, по которому строятся виртуальные базовые классы, соответствует поряд­ку их появления в объявлении класса. После вызова всех конструкторов виртуальных базовых классов вызываются конструкторы невиртуальных. И здесь порядок вызова зависит от порядка появления в объявлении.

Рис. 10.4. Дерево наследования с виртуальными и невиртуальными базовыми классами

Соседние файлы в папке Zaochniki