Бьерн Страуструп.
Язык программирования С++
166
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();
Бьерн Страуструп.
Язык программирования С++
167
};
Теперь
функция 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 наглядным или нет.
Достарыңызбен бөлісу: