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