Какие операторы явного приведения типов существуют в C++?

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

Ответ

В C++ для безопасности и ясности кода вместо C-style приведения (type)value рекомендуется использовать четыре оператора явного приведения:

  1. static_cast<NewType>(expression)

    • Назначение: Основное «безопасное» приведение для семантически совместимых типов.
    • Проверка: На этапе компиляции.
    • Примеры:

      double d = 3.14159;
      int i = static_cast<int>(d); // Преобразование числа
      
      void* ptr = malloc(100);
      char* charPtr = static_cast<char*>(ptr); // Приведение void* к конкретному типу указателя
      
      class Base {};
      class Derived : public Base {};
      Derived* d = new Derived();
      Base* b = static_cast<Base*>(d); // Восходящее приведение в иерархии
  2. dynamic_cast<NewType>(expression)

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

      class Base { public: virtual ~Base() {} };
      class Derived : public Base {};
      
      Base* b = new Derived();
      Derived* d = dynamic_cast<Derived*>(b); // Успешно
      
      Base* b2 = new Base();
      Derived* d2 = dynamic_cast<Derived*>(b2); // d2 будет nullptr
  3. const_cast<NewType>(expression)

    • Назначение: Единственный способ добавить или убрать квалификаторы const и volatile.
    • Внимание: Применять крайне осторожно. Изменение const объекта, изначально объявленного как константный, ведет к неопределенному поведению.
    • Пример (легальный случай — снятие const с указателя на не-const данные):

      void print(char* str) { /*...*/ }
      
      const char* message = "Hello";
      // print(message); // Ошибка компиляции
      print(const_cast<char*>(message)); // Возможно, если функция не меняет данные
  4. reinterpret_cast<NewType>(expression)

    • Назначение: Низкоуровневое, опасное приведение, которое интерпретирует битовое представление одного типа как другой. Зависит от платформы.
    • Использование: Крайне редко, например, для взаимодействия с железом или при сериализации.
    • Пример:
      int ipAddress = 0xC0A80101; // 192.168.1.1
      char* bytes = reinterpret_cast<char*>(&ipAddress);
      // Теперь bytes указывает на память, содержащую ipAddress

Правило: Всегда предпочитайте static_cast, dynamic_cast, const_cast или reinterpret_cast C-style cast. Они четко указывают намерение и ограничивают круг возможных преобразований, делая код безопаснее.