← Назад к вопросам

В чем разница между static_cast, dynamic_cast и reinterpret_cast?

2.0 Middle🔥 192 комментариев
#ООП и проектирование#Язык C++

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Три типа явного приведения типов в C++

C++ предоставляет три типа именованных приведений типов (named casts), которые имеют разные назначение и семантику. Это замена небезопасному C-стилю приведению (Type)variable.

1. static_cast: Компилятор проверяет, runtime не проверяет

static_cast — это приведение типов, которое проверяется во время компиляции компилятором. Runtime никакой проверки не делает.

Использование:

  • Приведение между связанными типами
  • Числовые конверсии
  • Указатели в иерархии наследования (UP-CAST безопасен, DOWN-CAST опасен!)
int x = 42;
double y = static_cast<double>(x);
char c = ''A'';
int n = static_cast<int>(c);

class Animal {};
class Dog : public Animal {};
Dog dog;
Animal* animal_ptr = static_cast<Animal*>(&dog);

Компилятор проверяет:

  • Правильность синтаксиса
  • Логичность приведения

Runtime не проверяет:

  • Действительно ли объект является нужным типом
  • Это ваша ответственность!

2. dynamic_cast: Runtime проверяет полиморфно

dynamic_cast — это приведение типов, которое проверяется во время выполнения (runtime). Требует RTTI (Run-Time Type Information) и виртуального деструктора.

Использование:

  • Безопасное приведение указателей в иерархии наследования
  • Проверка действительного типа объекта
  • Только с полиморфными классами (имеют виртуальные функции)
class Animal {
public:
    virtual ~Animal() {}
    virtual void sound() = 0;
};

class Dog : public Animal {
public:
    void sound() override { std::cout << "Woof!" << std::endl; }
    void fetch() { std::cout << "Fetching!" << std::endl; }
};

Animal* animal_ptr = new Dog();
Dog* dog_ptr = dynamic_cast<Dog*>(animal_ptr);
if (dog_ptr) {
    dog_ptr->fetch();
} else {
    std::cout << "Not a Dog!" << std::endl;
}

Требования для dynamic_cast:

  1. Классы должны быть полиморфны (иметь виртуальные функции)
  2. Класс должен иметь виртуальный деструктор
  3. RTTI должна быть включена

3. reinterpret_cast: Опасное переинтерпретирование битов

reinterpret_cast — это приведение типов, которое просто переинтерпретирует биты в памяти без каких-либо проверок. Это самое опасное приведение!

Использование:

  • Указатель к целому числу
  • Преобразование между несвязанными типами
  • Низкоуровневые операции
int* ptr = new int(42);
uintptr_t address = reinterpret_cast<uintptr_t>(ptr);

uintptr_t addr = 0x12345678;
int* dangerous_ptr = reinterpret_cast<int*>(addr);

Сравнение всех трёх

CastПроверкаКогдаБезопасность
static_castВо время компиляцииЛогичные преобразованияСреднее
dynamic_castВо время выполненияПолиморфные иерархииВысокое
reinterpret_castНет проверокНизкоуровневоеОчень низкое

Практические примеры

Пример 1: Иерархия наследования

Хорошо: dynamic_cast с проверкой

class Shape { virtual ~Shape() {} };
class Circle : public Shape {};

void processShape(Shape* shape) {
    Circle* circle = dynamic_cast<Circle*>(shape);
    if (circle) {
        circle->drawCircle();
    }
}

Пример 2: Числовые преобразования

static_cast для чисел:

double pi = 3.14159;
int rounded = static_cast<int>(pi);

Правила использования

Используй static_cast когда:

  • Преобразуешь между численными типами
  • UP-CAST в иерархии (Child* к Parent*)
  • Хочешь явно показать намерение

Используй dynamic_cast когда:

  • Нужно безопасное DOWN-CAST (Parent* к Child*)
  • Хочешь проверить действительный тип
  • Работаешь с полиморфными иерархиями

Используй reinterpret_cast когда:

  • Преобразуешь указатель в целое число
  • Работаешь с низкоуровневым кодом
  • Нет альтернативы

Резюме

Хорошая практика: Используй dynamic_cast для безопасности
Плохая практика: Избегай reinterpret_cast и C-style casts

Выбирай правильный cast в зависимости от ситуации!

В чем разница между static_cast, dynamic_cast и reinterpret_cast? | PrepBro