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

Дублирование подобъектов

Рассмотрим следующую систему классов.

classTop{public: // ...private: int top_; }; class Left : public Top { public: // ... private: int left_; }; class Right : public Top { public: // ... private: int right_; }; class Bottom : public Left, public Right { kj public: // ... private: int bottom_; }; // Код клиента int main() { Bottom bm; // ... }

Объект bmклассаBottomбудет содержать пять полей. В их число будут входить:

  1. bottom_ – собственное поле,

  2. left_ – поле, наследуемое от классаLeft,

  3. right_ – поле, наследуемое от классаRight,

  4. top_ – поле, наследуемое от классаTopпо ветвиLeft–Top,

  5. top_ – поле, наследуемое от классаTopпо ветвиRight–Top,

Для устранения дублирования базового подобъекта применяют так называемое виртуальное наследование. Для реализации виртуального наследования в рассматриваемом примере необходимо в базовые списки классов LeftиRightнеобходимо включить зарезервированное словоvirtual.

class Top { // ... }; class Left : virtual public Top { // ... }; class Right : virtual public Top { // ... }; class Bottom : public Left, public Right { // ... }; // Код клиента int main() { Bottom bm2; // ... }

Теперь объект (bm2) классаBottomбудет содержать четыре поля. В их число будут входить:

  1. bottom_ – собственное поле,

  2. left_ – поле, наследуемое от классаLeft,

  3. right_ – поле, наследуемое от классаRight,

  4. top_ – поле, наследуемое от классаTop.

При использовании виртуального наследования возникает дополнительная проблема, связанная с построением конструкторов.

Конструкторы при виртуальном наследовании

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

Реализация конструктора с параметрами для класса Bottom.

Bottom :: Bottom(int top, int left, int right, int bottom) : Left(one, left), Right(one, right), Top(one), bottom_(bottom) { }

Работа с данными при виртуальном наследовании

Предположим, что необходимо реализовать для каждого из классов, входящих в рассматриваемую в настоящем разделе систему классов, функцию Print(). Решение этой задачи показано ниже.

class Top { public: Top(); Top(int top); void Print() { Data(); } virtual ~Top(); protected: void Data() { cout << “one=” << one << endl; } private: int one_; }; class Left : virtual public Top { public: Left(); Left(int top, int left): Top(top), Left(left) { } void Print() { Top :: Print(); Data(); } virtual ~Left(); protected: void Data() { cout << “left=” << left_ << endl; } private: int left_; }; class Right : virtual public Top { <самостоятельно написать реализацию> }; class Bottom : public Left, public Right { public: Bottom(); Bottom(int top, int left, int right, int bottom) : Top(top), Left(one, left), Right(one, right), bottom_(bottom) { } void print() { One :: Data(); Left :: Data(); Right :: Data(); Data(); } private: Data() { cout << “bottom=” << bottom_ << endl; } int bottom_; };

Соседние файлы в предмете Программирование