Вопрос 25: Множественное наследование. Множественное вхождение базового класса. Разрешение неоднозначности.
Один класс может наследовать атрибуты двух и более классов одновременно. Для этого используется список базовых классов, в котором каждый из базовых классов отделен от других запятой. Общая форма множественного наследования имеет вид:
class ИмяПорожденногоКласса: список базовых классов
{
...
};
Для доступа к членам порожденного класса, унаследованного от нескольких базовых классов, используются те же правила, что и при порождении из одного базового класса. Проблемы могут возникнуть в следующих случаях:
если в порожденном классе используется член с таким же именем, как в одном из базовых классов;
когда в нескольких базовых классах определены члены с одинаковыми именами. В этих случаях необходимо использовать оператор разрешения контекста для уточнения элемента, к которому осуществляется доступ, именем базового класса.
Пример
class A : public B { // B используется для связывания всех // задач в список (список диспетчера) // ... }; class C : public B { // link используется для связывания всех // изображаемых объектов (список изображений) // ... }; class D : public A, public C { // ... }; Естественно, у двух базовых классов могут быть функции-члены с одинаковыми именами: class A { // ... virtual info* inf(); }; class C { // ... virtual info* inf(); }; При использовании класса D подобная неоднозначность функций должна быть разрешена: void f(D* sp) { info* dip = sp->inf(); //ошибка: неоднозначность dip = sp->A::inf(); // нормально dip = sp->C::inf(); // нормально } Однако, явное разрешение неоднозначности хлопотно, поэтому для ее устранения лучше всего определить новую функцию в производном классе: class D : public A, public derived { // ... debug_info* get_debug() { debug_info* dip1 = task:get_debug(); debug_info* dip2 = displayed::get_debug(); return dip1->merge(dip2); } };
class X
{int key;};
class Y
{int key;};
class Z
{int key;};
class A : public X, public Y, public Z
{int key;
...............
key=X :: key + Y :: key + Z :: key;
...............
};
Так как объект порожденного класса состоит из нескольких частей, унаследованных от базовых классов, то конструктор порожденного класса должен обеспечивать инициализацию всех наследуемых частей. В списке инициализации в заголовке конструктора порожденного класса должны быть перечислены конструкторы всех базовых классов. Порядок выполнения конструкторов при порождении из нескольких классов следующий:
конструкторы базовых классов в порядке их задания;
конструкторы членов, являющихся объектами класса;
конструктор порожденного класса.
Деструкторы вызываются в порядке обратном вызову конструкторов.
Пример:
#include <iostream>
using namespace std;
class X {
protected:
int key;
public:
X (int i=0) {cout << "X constructor" << endl; key = i;};
~X() {cout << "X destroyed" << endl; cin.get();};
};
class Y {
protected:
int key;
public:
Y (int i=0) {cout << "Y constructor" << endl; key = i;};
~Y() {cout << "Y destroyed" << endl; cin.get();};
};
class Z {
protected:
int key;
public:
Z (int i=0) {cout << "Z constructor" << endl; key = i;};
~Z() {cout << "Z destroyed" << endl; cin.get();};
};
class A : public X, public Y, public Z {
int key;
public:
A(int i=0) : X(i+1), Y(i+2), Z(i+3)
{ key = X::key + Y::key + Z::key; }
int getkey(void) {return(key);}
};
int main() {
A object(4);
cout << "object.key = " << object.getkey();
cin.get();
return 0;
}
Результат:
X constructor
Y constructor
Z constructor
object.key = 18
Z destroyed
Y destroyed
X destroyed