Кастиниг, или было у отца четыре сына…

03d7f55fdc4640a187fce63bf8d5a679

Давно, сразу после института, получив нагоняй от лида за круглые скобочки я решил наконец раз и навсегда разобраться с кастингом. Я написал себе небольшую шпаргалочку. На долгие годы забыв о ее существовании я недавно, разбирая бумаги, наткнулся на нее. Возможно она кому-то пригодится.

В С++ существует четыре оператора, осуществляющих приведение типов. Это static_cast, dynamic_cast, const_cast, и reinterpret_cast.
По наследству из языка C нам еще досталась возможности кастить переменные так называемым C-like кастом, это такие круглые скобочки с типом внутри. За использование такого каста Мартин предлагал сразу отрубать руки, и если-бы менеджмент пошел ему навстречу, то половина нашей фирмы уже давно ходила-бы без рук. Что-бы хоть как-то руки уберечь, рассмотрим по порядку, что нам предлагает C++.

static_cast это самый простой и самый понятный из четырех братьев. Конвертация происходит во врем компиляции. Поскольку конвертация происходит во время компиляции, компилятор может выругаться, если посчитает, что ему подсовывают то, что не конвертируется из одного в другое. static_cast вызывает явные или неявные функции конвертирования. Оператор производит проверку типов, поэтому всякие фокусы с приватными или защищенными перемнными не прокатывают. Простенько и со вкусом.

const_cast — наш следующий дружок. Он посложнее чем static_cast и несет в себе небольшие грабельки. Как нам сообщает документация, этот вид кастинга существует для того, что-бы сносить константность переменной, например, можно снести константность переменной внутри константного метода. Другими словами такое легальное средство взлома. Скажем получила функция константный this, а мы его хряпнули, и он уже никакой не конст. Не знаю, кому это может понадобиться, надо спросить у Мартина.

Еще одно полезное извращение, связанное с ним, это передача константы в функцию, которая не собиралась принимать константу. Частенько это функции какой-нибудь древней библиотеки, которую уже никто никогда не поправит. Что из этого может получиться, остается только гадать. Поэтому, дети, пишите в сигнатурах своих функций слово const, не прогадаете.
Особенно радует непредсказуемое поведение, если мы снесем константность у переменной, которая была константной по рождению, и после этого попробуем ее модифицировать, ведь константной ее кто-то сделал не зря. Он хотел облегчить жизнь компилятору, тот как ребенок поверил и запихнул ее в надежное место, а мы ее чик и модифицировали.
Разные по типу объекты, к слову, не кастятся, из чего мы делаем вывод, что этот каст то-же происходит в момент компиляции. Некоторые просветленные умы сносят этим кастом атрибут volatile, а кстати что это за хрень? Одним словом использование этого каста явно указывает на проблемы с сигнатурами.

reinterpret_cast — самый опасный из братьев. Он конвертирует указатели, при этом вообще не смотрит на то, что получилось, а указатели могут быть не связаны друг с другом. О нем сказано немало плохих слов, такой волшебник-недоумок. Может превратить все, что угодно во все, что угодно, но без гарантий. При компиляции этот фрукт не оставляет каких либо процессорных команд, а лишь говорит, каким образом интерпретировать произвольный кусок памяти. Интересная деталь, конструкторы и операторы не вызываются, нулевой указатель в указатель конвертировать нельзя, для этого, правда, можно воспользоваться static_cast-ом. Всегда что-то возвращает, даже если это мусор.

dynamic_cast — пожалуй единственный, имеющий право на существование, каст рантайма, так как он нужен для работы с иерархией классов и в случае неудачи делает что-то осязаемое, что можно потрогать, вроде нулевого указателя или генерации исключения.

И напоследок, когда C++ компилятор видит C-like каст, он не отрубает руки, как советовал Мартин, а честно пытается в контексте выбрать один из доступных ему кастов. Но если уж совсем честно — любой каст это кривые руки архитектора или программиста.

Habrahabr.ru прочитано 2871 раз