Бьерн Страуструп - Язык программирования С++. Главы 5-8
Страница 41. Разрешение неоднозначности



6.5.2 Разрешение неоднозначности

 Естественно, у двух базовых классов могут быть функции-члены
 с одинаковыми именами:

          class task {
             // ...
             virtual debug_info* get_debug();
          };

          class displayed {
             // ...
             virtual debug_info* get_debug();
          };

 При использовании класса satellite подобная неоднозначность функций
 должна быть разрешена:

          void f(satellite* sp)
          {
           debug_info* dip = sp->get_debug(); //ошибка: неоднозначность
           dip = sp->task::get_debug();       // нормально
           dip = sp->displayed::get_debug();  // нормально
          }

 Однако, явное разрешение неоднозначности хлопотно, поэтому
 для ее устранения лучше всего определить новую функцию в
 производном классе:

          class satellite : public task, public derived {
             // ...
             debug_info* get_debug()
             {
               debug_info* dip1 = task:get_debug();
               debug_info* dip2 = displayed::get_debug();
               return dip1->merge(dip2);
             }
          };

 Тем самым локализуется информация из базовых для satellite классов.
 Поскольку satellite::get_debug() является переопределением функций
 get_debug() из обоих базовых классов, гарантируется, что именно она
 будет вызываться при всяком обращении к get_debug() для объекта
 типа satellite.
     Транслятор выявляет коллизии имен, возникающие при определении
 одного и того же имени в более, чем одном базовом классе. Поэтому
 программисту не надо указывать какое именно имя используется, кроме
 случая, когда его использование действительно неоднозначно. Как правило
 использование базовых классов не приводит к коллизии имен. В большинстве
 случаев, даже если имена совпадают, коллизия не возникает, поскольку
 имена не используются непосредственно для объектов производного класса.
     Аналогичная проблема, когда в двух классах есть функции с одним
 именем, но разным назначением, обсуждается в $$13.8 на примере
 функции draw() для классов Window и Cowboy.
     Если неоднозначности не возникает, излишне указывать имя
 базового класса при явном обращении к его члену. В частности, если
 множественное наследование не используется, вполне достаточно
 использовать обозначение типа "где-то в базовом классе". Это
 позволяет программисту не запоминать имя прямого базового класса и
 спасает его от ошибок (впрочем, редких), возникающих при перестройке
 иерархии классов. Например, в функции из $$6.2.5

         void manager::print()
         {
           employee::print();
           // ...
         }

 предполагается, что employee - прямой базовый класс для manager.
 Результат этой функции не изменится, если employee окажется косвенным
 базовым классом для manager, а в прямом базовом классе функции
 print() нет. Однако, кто-то мог бы следующим образом перестроить
 классы:

         class employee {
           // ...
           virtual void print();
         };

         class foreman : public employee {
           // ...
           void print();
         };

         class manager : public foreman {
           // ...
           void print();
         };

 Теперь функция foreman::print() не будет вызываться, хотя почти
 наверняка предполагался вызов именно этой функции. С помощью
 небольшой хитрости можно преодолеть эту трудность:

         class foreman : public employee {
           typedef employee inherited;
           // ...
           void print();
         };

         class manager : public foreman {
           typedef foreman inherited;
           // ...
           void print();
         };

         void manager::print()
         {
           inherited::print();
           // ...
         }

 Правила областей видимости, в частности те, которые относятся к
 вложенным типам, гарантируют, что возникшие несколько типов
 inherited не будут конфликтовать друг с другом. В общем-то дело
 вкуса, считать решение с типом inherited наглядным или нет.

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