static_cast
– это первое заклинание, которое вы должны попытаться использовать. Он выполняет такие вещи, как неявные преобразования между типами (например, int
в float
или указатель на void*
), а также может вызывать функции явного преобразования (или неявные). Во многих случаях явное указание static_cast
не требуется, но важно отметить, что синтаксис T(something)
эквивалентен (T)something
, и его следует избегать (подробнее об этом позже). Однако T(something, something_else)
безопасен и гарантированно вызовет конструктор.
static_cast
также может использовать иерархию наследования. В этом нет необходимости при приведении вверх (к базовому классу), но при приведении вниз его можно использовать, если оно не приводит к наследованию virtual
. Однако проверка не выполняется, и поведение static_cast
вниз по иерархии к типу, который на самом деле не является типом объекта, является неопределенным.
const_cast
можно использовать для удаления или добавления const
к переменной; никакое другое приведение C++ не может его удалить (даже reinterpret_cast
). Важно отметить, что изменение прежнего const
value не определено только в том случае, если исходная переменная равна const
; если вы используете его, чтобы удалить const
из ссылки на что-то, что не было объявлено с помощью const
, это безопасно. Это может быть полезно, например, при перегрузке функций-членов на основе const
. Его также можно использовать для добавления const
к объекту, например, для вызова перегрузки функции-члена.
const_cast
также работает аналогично на volatile
, хотя это менее распространено.
dynamic_cast
используется почти исключительно для обработки полиморфизма. Вы можете преобразовать указатель или ссылку на любой полиморфный тип в любой другой тип класса (полиморфный тип имеет по крайней мере одну виртуальную функцию, объявленную или унаследованную). Вы можете использовать его не только для заброса вниз — вы можете забрасывать вбок или даже вверх по другой цепочке. dynamic_cast
найдет нужный объект и вернет его, если это возможно. Если это невозможно, он вернет nullptr
в случае указателя или выбросит std::bad_cast
в случае ссылки.
Однако у dynamic_cast
есть некоторые ограничения. Это не работает, если в иерархии наследования есть несколько объектов одного типа (так называемый «ужасный бриллиант») и вы не используете virtual
inheritance. Он также может проходить только через открытое наследование — он всегда не сможет пройти через наследование protected
или private
. Однако это редко является проблемой, поскольку такие формы наследования встречаются редко.
reinterpret_cast
— самый опасный бросок, и его следует использовать очень экономно. Он превращает один тип напрямую в другой — например, приведение значения из одного указателя к другому, или сохранение указателя в int
, или всевозможные другие неприятные вещи. По большому счету, единственная гарантия, которую вы получаете с reinterpret_cast
, заключается в том, что обычно, если вы возвращаете результат обратно к исходному типу, вы получите точно такое же значение (но нет, если промежуточный шрифт меньше исходного). Есть ряд конверсий, которые reinterpret_cast
тоже не может выполнить. Он используется в основном для особенно странных преобразований и битовых манипуляций, таких как преобразование необработанного потока данных в фактические данные или сохранение данных в младших битах выровненного указателя.