Бьерн Страуструп.
Язык программирования С++
345
конечно, имеет смысл учесть в программе отдельно вариант с slist. Допустив возможность определения
истинного типа параметра, задающего множество, функцию my(set&) можно записать так:
void my(set& s)
{
if (ref_type_info(s) == static_type_info(slist_set)) {
// сравнение двух представлений типа
// s
типа slist
slist& sl = (slist&)s;
for (T* p = sl.first(); p; p = sl.next()) {
// эффективный вариант в
расчете на list
}
}
else
{
for ( T* p = s.first(); p; p = s.next()) {
// обычный вариант для произвольного множества
}
}
//
...
}
Как только стал известен конкретный тип slist, стали доступны определенные операции со списками, и
даже стала возможна реализация основных операций подстановкой.
Приведенный вариант
функции действует отлично, поскольку slist - это конкретный класс, и
действительно имеет смысл отдельно разбирать вариант, когда параметр является slist_set.
Рассмотрим теперь такую ситуацию, когда желательно отдельно разбирать вариант как для класса, так
и для всех его производных классов. Допустим, мы имеем класс dialog_box из $$13.4 и хотим узнать,
является ли он классом dbox_w_str. Поскольку может существовать много
производных классов от
dbox_w_str, простую проверку на совпадение с ним нельзя считать хорошим решением. Действительно,
производные классы могут представлять самые разные варианты запроса строки. Например, один
производный от dbox_w_str класс может предлагать пользователю варианты строк на выбор,
другой
может обеспечить поиск в каталоге и т.д. Значит, нужно проверять и на совпадение со всеми
производными от dbox_w_str классами. Это так же типично для узловых классов,
как проверка на
вполне определенный тип типична для абстрактных классов, реализуемых конкретными типами.
void f(dialog_box& db)
{
dbox_w_str* dbws = ptr_cast(dbox_w_str, &db);
if (dbws) { // dbox_w_str
// здесь можно использовать dbox_w_str::get_string()
}
else
{
//
``
обычный'' dialog_box
}
//
...
}
Здесь "операция" приведения ptr_cast() свой второй параметр (указатель) приводит к своему первому
параметру (типу) при условии, что указатель настроен на объект тип, которого совпадает с заданным
(или является производным классом от заданного типа). Для проверки типа dialog_box используется
указатель, чтобы после приведения его можно было сравнить с нулем.
Возможно альтернативное решение с помощью ссылки на dialog_box:
void g(dialog_box& db)
{
try
{
dbox_w_str& dbws = ref_cast(dialog_box,db);
// здесь можно использовать dbox_w_str::get_string()
}
catch (Bad_cast) {
Бьерн Страуструп.
Язык программирования С++
346
//
``
обычный'' dialog_box
}
//
...
}
Поскольку нет приемлемого представления нулевой ссылки, с которой можно сравнивать, используется
особая ситуация, обозначающая ошибку приведения (т.е. случай, когда тип не есть dbox_w_str). Иногда
лучше избегать сравнения с результатом приведения.
Различие функций ref_cast() и ptr_cast() служит хорошей иллюстрацией различий между ссылками и
указателями: ссылка обязательно
ссылается на объект, тогда как указатель может и не ссылаться,
поэтому для указателя часто нужна проверка.
Достарыңызбен бөлісу: