Главная->Інформатика та програмування->Содержание->Неопределенность при множественном наследовании

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 9) онлайн

Неопределенность при множественном наследовании

В определенных ситуациях могут появиться некоторые проблемы, связанные со множественным наследованием. Здесь мы рассмотрим наиболее общую. Допус- тим, что в обоих базовых классах существуют методы с одинаковыми именами, а в производном классе метода с таким именем нет. Как в этом случае объект производного класса определит, какой из методов базовых классов выбрать? Одного имени метода недостаточно, поскольку компилятор не сможет вычис- лить, какой из двух методов имеется в виду. Эту ситуацию мы разберем в примере AMBIGU:

// ambigu.cpp

// демонстрация неопределенности при множественном наследовании

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////////

class A

{

  public:

    void show ( ) { cout << "Класс A\n"; }

};

class B

{

  public:

    void show ( ) { cout << "Класс B\n"; }

};

class C : public A, public B

{

};

///////////////////////////////////////////////////////////

int main ( )

{

  C objC;           // объект класса C

  // objC.show ( ); // так делать нельзя – программа не скомпилируется

  objC.A::show ( ); // так можно

  objC.B::show ( ); // так можно

  return 0;

}

Проблема решается путем использования оператора разрешения, определя- ющего класс, в котором находится метод. Таким образом,

ObjC.A::show ( );

направляет нас к версии метода show(), принадлежащей классу A, а objC.B::show ( );

направляет нас к методу, принадлежащему классу B, Б. Страуструп (см. прило- жение 3 «Библиография») называет это устранением неоднозначности.

Другой вид неопределенности появляется, если мы создаем производный класс от двух базовых классов, которые, в свою очередь, являются производны- ми одного класса. Это создает дерево наследования в форме ромба. В программе DIAMOND показано, как это выглядит.

//diamond.cpp

// демонстрация наследования в форме ромба #include <iostream>

using namespace std;

////////////////////////////////////////////////////////////////

class A

   {

   public:

      virtual void func();

   };

class B : public A

   {  };

class C : public A

   {  };

class D : public B, public C

   {  };

////////////////////////////////////////////////////////////////

int main()

{

   D objD;

   objD.func();  //неоднозначность: программа не скомпилируется

   return 0;

}

 

Классы В и C являются производными класса A, а класс D является произ- водным классов В и C. Трудности начинаются, когда объект класса D пытается воспользоваться методом класса A. В этом примере объект objD использует метод func(). Однако классы В и C содержат в себе копии метода func(), унасле- дованные от класса A. Компилятор не может решить, какой из методов исполь- зовать, и сообщает об ошибке.

Существует множество вариаций этой проблемы, поэтому многие эксперты советуют избегать множественного наследования. Не следует использовать его в своих важных программах, пока у вас нет достаточного опыта.

 

35