Различные касты в C++

Наткнулся на полезное видео про приведение типов в C++. Освежил знания в голове. Чтобы не забыть, тут запишу, вдруг пригодится. Видео встроено в конце статьи, можете промотать до него, если текст вам неинтересен, видео более подробное.
Автору видео и ведущему канала моё почтение — ролик про lvalue/rvalue я так полностью и не усвоил. Итак, основные способы приведения типов в языке С++ следующие:

static_cast

Проверка производится во время компиляции, сообщение о невозможности операции будет получено в момент сборки приложения. Осуществляет явное допустимое приведение типов данных, в основном, используется для преобразования между числовыми типами данных.
Нужно быть внимательным, если используете для приведения указателя на родительский класс (Base *) к указателю на наследника (Derived *), он не выполняет проверку на корректность приведения (только порядок наследования) в этом случае и молча создаст проблемы — не надо так! Лучше использовать для этого dynamic_cast.

Личный опыт: использую для того, чтобы компилятор не ругался на signed/unsigned типы и float/double.

dynamic_cast

Проверка производится во время исполнения. В случае неправильного приведения указателей будет возвращен 0, в случае ссылок исключение std::bad_cast. Использует RTTI, работает динамически, может применяться только к классам, которые имеют хоть одну виртуальную функцию (в которых есть таблица виртуальных методов).

Личный опыт: dynamic_cast предпочитаю использовать только для приведения указателя на родительский класс (Base *) к указателю на наследника (Derived *) с проверкой на 0. Никогда не использую его для ссылок, чтобы не париться с исключениями.

reinterpret_cast

Приведение указателей любых типов друг в друга без проверки, на ваш страх и риск. Говорит считать кусок памяти одного типа куском памяти другого типа. Был указатель на массив uint8_t, стал указатель на массив float. Что интересно: не генерирует код, не создаёт новых переменных. Он не изменяет битовое представление данных, а просто интерпретирует их по-другому.

Личный опыт: reinterpret_cast обычно использую, чтобы передавать различные типы через сырой указатель на область памяти (void*), но однажды я посмотрел, как побитово устроен float, и под впечатлением от увиденного написал целую статью.

const_cast

Убирает const и volatile модификаторы с переменной.

Личный опыт: даже не знаю, для чего он вам может понадобиться. В голову приходит перегрузка операторов:
T &operator[](index) и const T& operator[](index) const и вызов константного оператора из неконстантного с помощью const_cast, чтобы не дублировать код.

C-style cast

Применяет цепочку преобразований, сначала const_cast, потом static_cast, потом static_cast от const_cast, потом reinterpret_cast, потом reinterpret_cast от const_cast. Здорово, правда? Не рекомендую вам его использовать в C++.

Личный опыт: грешен, использую, когда лень много писать, но стараюсь его избегать и вам советую, потому что его невозможно найти поиском по файлу, только просматривая каждую строку глазами, а они не вечные.
Вообще, всю жизнь считал, что это аналог reinterpret_cast, но я ошибался.

std::static_pointer_cast

Аналог static_cast для приведения умных указателей std::shared_ptr.

Личный опыт: std::static_pointer_cast использую для приведения умных указателей на базовый класс (std::shared_ptr<Base>) к умному указателю на наследованный класс (std::shared_ptr<Derived>).

std::dynamic_pointer_cast

Аналог dynamic_cast для умных указателей std::shared_ptr.

Личный опыт: никогда не видел вживую и не использовал, узнал про него в сейчас лет.

std::const_pointer_cast

Аналог const_cast для умных указателей std::shared_ptr.

Личный опыт: узнал про последние два только во время написания этой статьи, никогда не использовал. Буду «блистать» на собесах.

Видео по теме

Комментариев нет. Будьте первым!
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Личный блог Евгения Жирнова