Язык программирования C++ для профессионалов


Виртуальные базовые классы - часть 3


class window { // головная информация void _draw(); void draw(); };

Для производных классов эффект тот же:

class window_w_border : public virtual window { // класс "окно с рамкой" // определения, связанные с рамкой void _draw(); void draw(); };

void window_w_border::draw() { window::_draw(); _draw(); // рисует рамку };

Только для производного класса следующего уровня проявляется отличие функции, которое и позволяет обойти ловушку с повторным вызовом window::draw(), поскольку теперь вызывается window::_draw() и только один раз:

class window_w_border_and_menu : public virtual window, public window_w_border, public window_w_menu {

void _draw(); void draw(); };

void window_w_border_and_menu::draw() { window::_draw(); window_w_border::_draw(); window_w_menu::_draw();

_draw(); // теперь операции, относящиеся только // к окну с рамкой и меню }

Не обязательно иметь обе функции window::draw() и window::_draw(), но наличие их позволяет избежать различных простых описок.

В этом примере класс window служит хранилищем общей для window_w_border и window_w_menu информации и определяет интерфейс для общения этих двух классов. Если используется единственное наследование, то общность информации в дереве классов достигается тем, что эта информация передвигается к корню дерева до тех пор, пока она не станет доступна всем заинтересованным в ней узловым классам. В результате легко возникает неприятный эффект: корень дерева или близкие к нему классы используются как пространство глобальных имен для всех классов дерева, а иерархия классов вырождается в множество несвязанных объектов.

Существенно, чтобы в каждом из классов-братьев переопределялись функции, определенные в общем виртуальном базовом классе. Таким образом каждый из братьев может получить свой вариант операций, отличный от других. Пусть в классе window есть общая функция ввода get_input():

class window { // головная информация virtual void draw(); virtual void get_input(); };

В одном из производных классов можно использовать эту функцию, не задумываясь о том, где она определена:




- Начало -  - Назад -  - Вперед -