Вопрос 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;
...............
};

Так как объект порожденного класса состоит из нескольких частей, унаследованных от базовых классов, то конструктор порожденного класса должен обеспечивать инициализацию всех наследуемых частей. В списке инициализации в заголовке конструктора порожденного класса должны быть перечислены конструкторы всех базовых классов. Порядок выполнения конструкторов при порождении из нескольких классов следующий:

  1. конструкторы базовых классов в порядке их задания;

  2. конструкторы членов, являющихся объектами класса;

  3. конструктор порожденного класса.

Деструкторы вызываются в порядке обратном вызову конструкторов.

Пример:

#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

results matching ""

    No results matching ""