const_cast и reinterpret_cast
Представьте вещь в музейной витрине с табличкой «только смотреть». Смотреть на неё может любой, а трогать нельзя никому. const у переменной — такая табличка: значение можно читать, но не менять.
static_cast меняет тип значения, но снять const с указателя он не может:
int main() {
const int limit = 10;
int* p = static_cast<int*>(&limit); // ✗
return *p;
}error: static_cast from 'const int *' to 'int *' is not allowedСнимать const и переинтерпретировать указатели умеют другие именованные приведения. У каждого из них одна задача.
const_cast
const_cast снимает const с указателя или ссылки и больше ничего не меняет: const_cast<int*>(&limit) — это int* на тот же limit. Тип значения он не меняет, поэтому const_cast<int>(2.5) не скомпилируется. Его применяют, когда функция принимает int*, но значение только читает:
#include <iostream>
void print_value(int* p) {
std::cout << *p << '\n';
}
int main() {
const int limit = 10;
print_value(const_cast<int*>(&limit)); // 10
}Без const_cast адрес const-переменной в такую функцию не передать: const int* в int* компилятор сам не превращает.
Здесь аналогия с витриной заканчивается важным правилом. const_cast снимает табличку только с вашего указателя, а сама вещь остаётся музейной. Если переменную объявили с const, менять её нельзя и после приведения.
reinterpret_cast и void*
С указателями reinterpret_cast даёт указатель на другой тип с тем же адресом. Байты в памяти остаются прежними: меняется только тип, через который программа их читает. Прочитать float через int* — неопределённое поведение, поэтому начинающему это приведение почти не нужно. Числа reinterpret_cast не преобразует: reinterpret_cast<int>(2.5) не скомпилируется.
Некоторые указатели меняют тип и без приведения. int* неявно превращается в void*, указатель на значение неизвестного типа. Обратно в int* его возвращает static_cast<int*>.
Четвёртое именованное приведение, dynamic_cast, работает только с указателями и ссылками на составные типы вроде struct, а с числами — нет.
Частая ошибка
Через const_cast записывают в переменную, объявленную с const:
int main() {
const int limit = 10;
int* p = const_cast<int*>(&limit);
*p = 20; // ✗
return limit;
}Компилятор собирает программу без ошибок и предупреждений. Но limit объявлена с const, и запись в неё через p — неопределённое поведение: стандарт не говорит, что вернёт main. Писать через const_cast можно только в переменную, объявленную без const. Если значение должно меняться, уберите const из объявления.
Главное
const_castснимаетconstс указателя или ссылки и не меняет тип значения.- Записывать через
const_castв переменную, объявленную сconst, — неопределённое поведение. reinterpret_castчитает те же байты как другой тип и числа не преобразует.int*неявно превращается вvoid*, а обратно его возвращаетstatic_cast<int*>.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.