Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Множественное наследование. Виртуальный базовый класс
Прямые базовые классы Множественное наследование имеет место, если список порождения содержит более одного базового класса. Например,
class C: public A, public B {....};
То есть схематично это выглядит так:
Функции, определенные в классах A и B в части public, доступны объекту класса C независимо от того, в каком классе они определены.
С x(...); // действует конструктор класса A, потом B, потом C x.Fa(); x.Fb();
Операция:: здесь не требуется, так как функции имеют разные имена. А если в классах A и B имелась бы функция с одинаковым именем, например, F(), то обращение к ней с объектом класса C должно содержать операцию::
x.A:: F(); или x.B:: F();
Конструктор класса C отвечает за инициализацию член-данных классов A и B, то есть должен иметь, например, такой вид:
C:: C(int x, int y, int z): A(x), B(y) {c = z;}
Рассмотренный пример – это пример множественного наследования с прямыми базовыми классами. Если же базовые классы A и B в свою очередь порождены от других базовых, то эти последние для класса C будут не прямыми базовыми (или косвенными). Приведем пример такого наследования.
Виртуальный базовый класс В случае косвенных базовых классов может возникнуть ошибочная ситуация. Рассмотрим, в чем она заключается. Пусть, например, имеется такая иерархия порождения
Рассмотрим пристальнее, что означает такое наследование: Эта схема показывает, что объект класса D будет содержать 2 копии член-данного int a класса A, что может привести к двусмысленности. Например, если в классе D есть функция
int D:: Geta() {return a;}
и член-данное a находится в части protected класса A, то компилятор все равно выдаст сообщение об ошибке – «двусмысленность»: так как непонятно член-данное a надо взять из части B:: A или C:: A. Избежать двусмысленности можно, указав явно класс B или C.
int D:: Geta() {return C:: a;}
Однако наличие в дереве наследования нескольких копий одного и того же базового класса не только вносит путаницу, но и приводит к лишним затратам памяти. Чтобы этого не происходило, базовый класс A в списке порождения надо объявить виртуальным: class B: public virtual A {...}; class C: public virtual A {...}; class D: public B, public C {...};
В этом случае в объектах классов B и C будут сформированы указатели на член-данные базового класса A. То есть картина будет такой:
Это представление классов соответствует такому дереву наследования:
Из рисунка видно, что в данном случае неоднозначности для член-данного a не будет, так как a – одна ячейка! Замечание. В рассмотренных двух способах порождения класса D: 1) не через виртуальный базовый класс A; 2) через виртуальный базовый класс A конструктор класса D определяется по-разному. В первом случае конструктор класса D не «заботится» об инициализации член-данных класса A, то есть определяется, например, так
D(int r, int s): B(r), C(s) {...}.
А во втором случае конструктор класса D отвечает и за инициализацию член-данных виртуального базового класса A. То есть должен быть задан, например, так
D(int r, int s, int q): A(r), B(s), C(q) {...}
В заключение рассмотрим пример наследования: порождение класса Kolobok из двух базовых классов Bar и Circ из п. 12 главы 1.
const int CF = 7; class Bar { protected: int h, w, x, y; public: Bar(int hh, int ww, int xx, int yy) {h = hh; w = ww; x = xx; y = yy;} void Show(int c) { } };
class Circ { int r; protected: int x, y; public: Circ(int rr, int xx, int yy) {r = rr; x = xx; y = yy;} void Show(int c) { } };
class Kolobok: public Circ, public Bar { int numb; char * name; // место и имя public: Kolobok(int h, int w, int x, int y, int r, int m, char * s): Bar(h, w, x, y), Circ(r, x + w / 2, y - r) {numb = m; name = new char [strlen(s) + 1]; strcpy(name, s); } ~Kolobok() {delete [ ] name;} void Show(int cb, int cc, int ck) {Bar:: Show(cb); Circ:: Show(cc); … } };
void main() {int x = 200, dx = 100, i; Kolobok klb[3] = {Kolobok(100, 50, x, 150, 40, 2, “два”), Kolobok(150, 50, x = x + dx, 100, 35, 1, “один”), Kolobok(50, 50, x = x + dx, 200, 30, 3, “три”) }; for(i = 0; i < 3; i++) klb[i].Show(4, 14, 12); Kolobok *pbc = new Kolobok(50, 50, 300, 400, 50, 4); pbc –> Show(3, 12, 14); delete pbc; }
|
|||||
Последнее изменение этой страницы: 2021-12-07; просмотров: 53; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.216.190.167 (0.006 с.) |