Заголовочный файл boost/cast.hpp содержит объявления шаблонов функций polymorphic_cast, polymorphic_downcast, и numeric_cast, предназначенных для дополнения встроенных функций преобразования (cast'ов) языка C++.
Программа cast_test.cpp в исходниках BOOST C++ используется для проверки правильной работы этих шаблонов функций.
Указатели на полиморфные объекты (экземпляры классов, которые содержат по крайней мере одну виртуальную функцию) допускают два типа преобразований: downcast или crosscast. Преобразование downcast означает преобразование от базового типа в производный тип. Crosscast означает преобразование между уровнями иерархии в диаграмме наследования, такое как преобразование от одного базового класса в другой в случае множественного наследования (в Y диаграмме).
Такие преобразования могут быть выполнены обычными cast'ами, хотя такой подход не рекомендуется. Таким преобразованиям не хватает типобезопасности, читабельности кода, кроме того их трудно найти в коде с помощью средств поиска.
Встроенный оператор преобразования языка C++ static_cast может быть использован для эффективного выполнения преобразования downcast указатеей на полиморфные объекты, но он не обеспечивает обнаружение ошибок, когда преобразуемый указатель на самом деле указывает на неверный производный класс. Шаблон polymorphic_downcast сохраняет эффективность преобразования static_cast для релиз-версий программ, а для отладочных версий добавляет проверку успешности преобразования через использование макроса assert() к результату вызова dynamic_cast.
Встроенный оператор преобразования языка C++
dynamic_cast может быть использован для
выполнения преобразований downcast и
crosscast указателей на полиморфные объекты, однако возврат 0 в случае
возникновения ошибок неудобно для тестов, а в
худшем случае приводит к отсутствию проверки, если
программист забыл об этом. Вызывающая исключение
форма dynamic_cast, которая работает со
ссылками, может быть использована через неуклюжее выражение &dynamic_cast<T&>(*p),
которое приводит к неопределенному поведению программы,
если p равен 0. Шаблон
polymorphic_cast
вызывает dynamic_cast для указателя, и
возбуждает исключение, если
dynamic_cast возвращает 0.
Преобразование с помощью шаблона polymorphic_downcast предпочтительно для тестирования в отладочном режиме (со 100% проверкой преобразований типов) и когда эффективность релиз-версии программы является существенной. Если оба этих условия не выполняются, тогда предпочтительнее использовать преобразование шаблоном polymorphic_cast. Он должен быть использован для преобразований категории crosscast. Этот шаблон выполняет проверку assert( dynamic_cast<Derived>(x) == x ), когда x является базовым указателем, гарантируя не только невозврат нулевого указателя, но и корректность преобразования при множественном наследовании. Замечание: Так как шаблон polymorphic_downcast использует макрос assert(), то будет нарушено правило единого определения шаблона (one definition rule - ODR), когда макрос NDEBUG определен по разному в разным транслируемых файлах [См. ISO Std 3.2]
Встроенный оператор преобразования языка C++ dynamic_cast должен использоваться для преобразования ссылок, а не указателей. Кроме того, это единственный шаблон преобразования, который должен использоваться для проверки, поддерживается ли объектом заданный интерфейс, в этом случае возврат 0 не является ошибкой.
Описание polymorphic_cast и polymorphic_downcast
namespace boost {
template <class Derived, class Base>
inline Derived polymorphic_cast(Base* x);
// Throws: std::bad_cast if ( dynamic_cast<Derived>(x) == 0 )
// Returns: dynamic_cast<Derived>(x)
template <class Derived, class Base>
inline Derived polymorphic_downcast(Base* x);
// Effects: assert( dynamic_cast<Derived>(x) == x );
// Returns: static_cast<Derived>(x)
}
Пример использования polymorphic_downcast
#include <boost/cast.hpp>
...
class Fruit { public: virtual ~Fruit(){}; ... };
class Banana : public Fruit { ... };
...
void f( Fruit * fruit ) {
// ... logic which leads us to believe it is a Banana
Banana * banana = boost::polymorphic_downcast<Banana*>(fruit); ...
Шаблон преобразования static_cast или неявное преобразование не могут обеспечить проверку возникновения ошибки переполнения (нарушения диапазона) при преобразовании чисел. Шаблонная функция numeric_cast похожа на static_cast и некоторые неявные преобразования такого типа, но она проверяет ситуацию нарушения представимого диапазона. При нарушении диапазона шаблон гунурирует исключение.
Аргумент и возвращаемое значение должны удовлетворять следующим условиям:
- аргумент и возвращаемый тип следуют парадигме CopyConstructible [ISO Std 20.1.3].
- аргумент и возвращаемый тип следуют парадигме Numeric, то есть выражение
std::numeric_limits<>::is_specializedдля них оценивается в true.- Аргумент может быть преобразован в возвращаемый тип через вызов static_cast.
Описание numeric_cast
namespace boost {
class bad_numeric_cast : public std::bad_cast {...};
template<typename Target, typename Source>
inline Target numeric_cast(Source arg);
// Throws: bad_numeric_cast unless, in converting arg from Source to Target,
// there is no loss of negative range, and no underflow, and no
// overflow, as determined by std::numeric_limits
// Returns: static_cast<Target>(arg)
}
Пример использования numeric_cast
#include <boost/cast.hpp>
using namespace boost::cast;
void ariane(double vx)
{
...
unsigned short dx = numeric_cast<unsigned short>(vx);
...
}
Обоснование для numeric_cast
Проверка на диапазон выполняется таким образом, что оператор != не используется.
История
polymorphic_cast был предложен Bjarne Stroustrup в "The C++ Programming Language".
polymorphic_downcast был реализован Dave Abrahams.
numeric_cast был реализован Kevlin Henney.
Revised 03 июня, 2005
© Copyright boost.org 1999. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
последняя правка: 03.06.2005
библиотека BOOST C++
http://www.boost.org
перевод
Elijah Koziev
www.solarix.ru