Какие виды приведения типов (cast) знаешь в C++?

«Какие виды приведения типов (cast) знаешь в C++?» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В C++ существует четыре основных вида явного приведения типов, каждый со своей семантикой и областью применения:

  1. static_cast — базовое приведение, проверяемое на этапе компиляции. Используется для преобразований между числовыми типами, указателями вверх/вниз по иерархии наследования (без проверки на этапе выполнения) и для явного вызова конструкторов/операторов преобразования.

    double d = 3.14;
    int i = static_cast<int>(d); // Преобразование double в int
    
    Base* basePtr = new Derived();
    Derived* derivedPtr = static_cast<Derived*>(basePtr); // Вниз по иерархии (опасно, если basePtr не указывает на Derived)
  2. dynamic_cast — предназначен для безопасного приведения вниз или вбок по иерархии полиморфных типов (классов с виртуальными функциями). Проверка осуществляется во время выполнения (RTTI). При неудаче для указателей возвращает nullptr, для ссылок — исключение std::bad_cast.

    Base* b = new Derived();
    Derived* d = dynamic_cast<Derived*>(b); // Успешно, если b действительно указывает на Derived
    if (d) {
        // Работаем с d
    }
  3. const_cast — используется для добавления или удаления квалификаторов const и volatile. Основное применение — работа с устаревшим кодом, где функция принимает неконстантный указатель, хотя данные не изменяются.

    void legacyFunction(char* str);
    const char* greeting = "Hello";
    // legacyFunction(greeting); // Ошибка компиляции
    legacyFunction(const_cast<char*>(greeting)); // Опасно, если legacyFunction модифицирует данные
  4. reinterpret_cast — низкоуровневое приведение, которое интерпретирует битовое представление объекта одного типа как объект другого типа. Крайне опасно и зависит от платформы (порядок байт, выравнивание). Используется, например, для приведения указателя к целочисленному типу или между несвязанными типами указателей.

    int* ip = new int(0x41424344);
    char* cp = reinterpret_cast<char*>(ip); // Интерпретируем память int как массив char
    // cp[0] может быть 'D' (ASCII 0x44) или 'A' (0x41) в зависимости от endianness

C-style cast (type)value в C++ пытается применить комбинацию static_cast, const_cast и reinterpret_cast и может быть неявным. Его использование не рекомендуется, так как оно менее безопасно и затрудняет поиск мест приведения в коде.