Множественное наследование: объявление, примеры реализации, недостатки. Виртуальное наследование

Как уже отмечалось, в С++ производный класс может быть порождён из любого числа непосредственных базовых классов. Наличие у производного класса более чем одного непосредственного базового класса называется множественным наследием. Синтаксически множественное наследование отличается от единичного наследования списком порождения, состоящим более чем из одного класса.

//Листинг 7. Пример множественного наследования

class A

{int a1;

public:

int a2;

void funcA()

};

class B

{int b1;

public:

int b2;

void funcB()

};

class C: public A, public B //наследуем класс С от A и B

{int c1;

public:

int c2;

void funcC()

};

Схема иерархии классов, определенных в последнем примере, изображена на рис.4

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

class A {public: int x; void funcA(); …};

class B: public A {…};

class D: public A{…};

class C: public B, public D {…};

Дублирование косвенного базового класса (рис 5а) приводит к включению в производный класс нескольких объектов базового класса. Для класса С в последнем примере это означает, что компонентное данное x будет существовать в объектах данного класса в двух экземплярах – один унаследован через класс В, другой – через класс D, что порождает проблему неоднозначности при доступе к дублирующимся компонентам класса: неясно, какой из одноименных компонент изменится при следующем обращении

main()

{ C c;

c.x=6; // Ошибка!!!

}

Попытка доступа к члену данных x для объекта с приводит к ошибке транслятора “Member is ambiguous A::x and A::x”. Эта ошибка означает, что транслятор не может определить, какому из двух компонент x класса необходимо присвоить новое значение. Неразрешимыми именами для транслятора будут также следующие с.C::x и c.A::x. Решением проблемы является использование квалифицированных имен компонент с использованием имен классов B и D. Для транслятора однозначно различаются следующие имена компонент: с.B::x (компонента, унаследованная через класс В) и c.D::x (компонента, унаследованная через класс D). Именно из-за сложности управления одноименными унаследованными компонентами класса множественное наследование реализаций было запрещено в языках программирования, появившихся после С++ (например, в C# и Java).

Еще один вариант множественного наследования классов в языке С++ - использование виртуальных базовых классов. Если компоненты косвенного базового класса не должны дублироваться в классе-потомке, то он объявляется виртуальным:

class D {…};

class A: public virtual D {…};

class B: public virtual D {…};

class C: public A, public B{…};

Диаграмма классов в этом случае будет выглядеть как на рис. 5б. Компоненты косвенного базового класса присутствуют в классе С в единственном экземпляре, проблемы неоднозначности доступа к ним не возникает.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: