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 наглядным или нет.


Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.