Класс называют непосредственным (прямым) базовым классом (прямой базой), если он входит в список базовых при определении класса. В то же время для производного класса могут существовать косвенные или непрямые предшественники, которые служат базовыми для классов, входящих в список базовых. Если некоторый класс Аявляется базовым для Ви Весть база дляС,то класс Вявляется непосредственным базовым классом для С, а класс А- непрямой базовый класс для С. Обращение к компоненту ха, входящему в А и унаследованному последовательно классами Ви С, можно обозначить в классе Слибо как А::ха, либо как В::ха. Обе конструкции обеспечивают обращение к элементу хакласса А.
Производные классы принято изображать ниже базовых. Именно в таком порядке их объявления рассматривает компилятор и их тексты размещаются в листинге программы. Класс может иметь несколько непосредственных базовых классов, т.е. может быть порожден из любого числа базовых классов, например:
class X1 { … };class X2 { … };class X3 { … };class Y1: public X1, public X2, public X3 { … };
Наличие нескольких прямых базовых классов называют множественным наследованием.
Определения базовых классов должны предшествовать их использованию в качестве базовых. При множественном наследовании никакой класс не может больше одного раза использоваться в качестве непосредственного базового. Однако класс может больше одного раза быть непрямым базовым классом:
class X { …; f (); … };class Y: public X { … };class Z: public X { … };class D: public Y, public Z { … };
В данном примере класс Х дважды опосредовано наследуется классом D.
Проиллюстрированное дублирование класса соответствует включению в производный объект нескольких объектов базового класса. В нашем примере существуют два объекта класса Х,и поэтому для устранения возможных неоднозначностей вне объектов класса D нужно обращаться к конкретному компоненту класса Х, используя полную квалификацию: D::Y::X::f()или D::Z::X::f(). Внутри объекта класса D обращения упрощаются Y::X::f()или Z::X::f(), но тоже содержат квалификацию.
Чтобы устранить дублирование объектов непрямого базового класса при множественном наследовании, этот базовый класс объявляют виртуальным. Для этого в списке базовых классов перед именем класса необходимо поместить ключевое слово virtual. Например, класс Хбудет виртуальным базовым классом при таком описании:
class X {… f() ; … };class Y: virtual public X { … };class Z: virtual public X { … };class D: public Y, public Z { … };
Теперь класс D будет включать только один экземпляр Х, доступ к которому равноправно имеют классы Y и Z.
Обратите внимание, что размеры производных классов при отсутствии виртуальных базовых равны сумме длин их компонентов и длин унаследованных базовых классов. “Накладные расходы” памяти здесь отсутствуют.
При множественном наследовании один и тот же базовый класс может быть включен в производный класс одновременно несколько раз, причем и как виртуальный, и как не виртуальный.
class X { … };class Y: virtual public X { … };class Z: virtual public X { … };class B: virtual public X { … };class C: virtual public X { … };class E: public X { … };class D: public X { … };class A: public D, public B, public Y, public Z, public C, public E { … };
В данном примере объект класса А включает три экземпляра объектов класса Х: один виртуальный, совместно используемый классами B, Y, C, Z, и два не виртуальных относящихся соответственно к классам D и E. Таким образом, можно констатировать, что виртуальность класса в иерархии производных классов является не свойством класса как такового, а результатом особенностей процедуры наследования.
Возможны и другие комбинации виртуальных и невиртуальных базовых классов. Например:
class BB { … };class AA: virtual public BB { … };class CC: virtual public BB { … };class DD: public AA, public CC, public virtual BB { … };
При использовании наследования и множественного наследования могут возникать неоднозначности при доступе к одноименным компонентам разных базовых классов. Простейший и самый надежный способ устранения неоднозначностей — использование квалифицированных имен компонентов. Как обычно, для квалификации имени компонента используется имя класса. Следующий пример иллюстрирует упомянутую неоднозначность и ее разрешение с помощью квалификационных имен компонентов:
Статьи к прочтению:
- Мобильность программного обеспечения. платформенно-независимый интерфейс posix
- Модели решений функциональный и вычислительных задач
С++ Виртуальные классы наследование.Программирование
Похожие статьи:
-
Проблемы множественного наследования классов. интерфейсы
Достаточно часто требуется совмещать в объекте поведение, характерное для двух или более независимых иерархий. Но ещё чаще требуется писать единый…
-
Наследование классов и производные классы
Начиная рассматривать вопросы наследования, нужно отметить, что обоснованно введенный в программу объект призван моделировать свойства и поведение…