Бьерн Страуструп - Язык программирования С++. Вступление, глава 1
Страница 39. Множественное наследование


 

1.5.3  Множественное наследование

    Если класс A является базовым классом для B, то B наследует атрибуты
A.  т.е. B содержит A плюс еще что-то. С учетом этого становится очевидно,
что хорошо, когда класс B может наследовать из двух базовых классов A1 и
A2. Это называется множественным наследованием.

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

       class my_displayed_task: public displayed, public task
       {
          // текст пользователя
       };

       class my_task: public task {
          // эта задача не изображается
          // на экране, т.к. не содержит класс displayed
          // текст пользователя
       };

       class my_displayed: public displayed
       {
          // а это не задача
          // т.к. не содержит класс task
          // текст пользователя
       };

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

    Все неоднозначности выявляются на стадии трансляции:

         class task
         {
         public:
           void trace ();
           // ...
         };

         class displayed
         {
         public:
           void trace ();
           // ...
         };

         class my_displayed_task:public displayed, public task
         {
           // в этом классе trace () не определяется
         };

         void g ( my_displayed_task * p )
         {
           p -> trace ();  // ошибка: неоднозначность
         }

    В этом примере видны отличия С++ от объектно-ориентированных диалектов
языка Лисп, в которых есть множественное наследование. В этих диалектах
неоднозначность разрешается так: или считается существенным порядок
описания, или считаются идентичными объекты с одним и тем же именем в
разных базовых классах, или используются комбинированные способы, когда
совпадение объектов доля базовых классов сочетается с более сложным
способом для производных классов. В С++ неоднозначность, как правило,
разрешается введением еще одной функции:

      class my_displayed_task:public displayed, public task
      {
          // ...
      public:
          void trace ()
          {
            // текст пользователя
            displayed::trace ();  // вызов trace () из displayed
            task::trace ();       // вызов trace () из task
          }
          // ...
     };

    void g ( my_displayed_task * p )
    {
       p -> trace ();  // теперь нормально
    }

 
« Предыдущая статья   Следующая статья »