- •1 Перегрузка функций
- •Шаблоны функций
- •Void main()
- •3 Класс — как расширенное понятие структуры
- •4 Конструкторы, деструкторы и доступность компонентов класса
- •Void main ( )
- •5 Компонентные данные
- •7 Указатель this
- •Void main()
- •8 Друзья классов
- •9 Перегрузка стандартных операций
- •Void main ()
- •10 Простое наследование
- •11 Виртуальные функции и абстрактные классы
- •12 Абстрактные классы
- •13 Множественное наследование
- •Void main()
13 Множественное наследование
Класс называют непосредственным (прямым) базовым класом (прямой базой), если он входит в список базовых классов при определении класса. В то же время для производного класса могут существовать косвенные или непрямые предшественники, которые служат базовыми для классов, входящих в список базовых. Если некоторый класс А является базовым для В и В есть база для С, то класс В является непосредственным базовым классом для С, а класс А – непрямой базовый класс для С. Обращение к компоненту ха, входящему в А и унаследованному последовательно классами В и С, можно обозначить в классе С либо как А::ха, либо как В::ха.
Иерархию производных классов удобно представлять с помощью направленного ациклического графа, где стрелкой изображают отношение "производный от". Производные классы принято изображать ниже базовых.
Класс может быть порожден из любого числа базовых классов.
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 {…};
c
lass
D:public Y, public Z{…};
Для обращения к конкретному компоненту класса X необходимо использовать полную квалификацию: 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 {…};
#
// Множественное наследование с виртуальным
базовым классом
include<iostream.h>
class base
{ int jj; char cc; char vv[10];
public:
base (int j=0, char c='*') { jj=j; cc=c;}
};
class dbase:virtual public base
{ double dd;
public:
dbase (double d=0.0):base() {dd=d;}
};
class fbase:virtual public base
{ float ff;
public:
fbase (float f=0.0):base() {ff=f;}
};
class top:public dbase, public fbase
{ long tt;
public:
top (long t=0):dbase(), fbase() { tt-t;}
};
Void main()
{ cout<<"\n Основной базовый класс"<<sizeof(base);
cout<<"\n Непосредственная база"<<sizeof(dbase);
cout<<"\n Непосредственная база"<<sizeof(fbase);
cout<<"\n Производный класс"<<sizeof(top);
}
14
Термины полиморфизм и позднее (динамическое) связывание обычно применяются, когда говорят о механизмах наследования и виртуальных функциях языка С++.
Полиморфизмом называют свойство базового класса, позволяющее ему обеспечивать взаимодействие с виртуальными функциями, которые могут по-разному определяться несколькими производными классами.
Термин позднее связывание относится к тому обстоятельству, что компилятор не может определить заранее, какая функция должна вызываться на самом деле, если обращение к виртуальной функции использует указатель или ссылку на базовый класс. Хотя переменная и определяется как указатель на базовый класс, она в действительности может указывать на объект производного класса. Эта особенность виртуального механизма приводит к тому, что адрес функции может быть найден только во время исполнения программы.
