Статьи

C ++ лаконично: приведение в C ++

Существует пять различных способов приведения переменных. Между ними есть частичное совпадение, особенно с бросками в стиле C и всеми остальными, но у каждого есть свое применение. Хорошо выучить их все, поэтому вы можете использовать лучший актерский состав для ваших конкретных нужд, а не использовать любой актерский состав, который работает. Если вам когда-нибудь понадобится краткая справка, я рекомендую этот пост в StackOverflow .

Я не обсуждаю неявное приведение здесь по той простой причине, что это базовая концепция с почти бесконечным числом вариаций. Если я напишу float f = 10; Я неявно бросил целое число в число с плавающей точкой и сохранил его результат в f. Вы также можете неявно приводить объект типа B к указателю на его базовый класс A, используя оператор адреса, или к ссылке на его базовый класс A, выполняя обычное присваивание.

Оператор const_cast может добавлять и удалять const и volatile. С его помощью можно добавить любой из этих атрибутов. Это редко, но вы можете.

Его способность удалять const — это то, что вы никогда не должны использовать в программе на C ++, кроме случаев, когда вам нужно вызвать функцию на языке C, которая не соблюдает правильность const, но не изменяет объект вообще. Если функция имеет параметр const и выбрасывает его постоянство с помощью const_cast, функция нарушает подразумеваемый контракт о том, что она не будет изменять параметр. Так что вы, как автор этой функции, должны убедиться, что вы не собираетесь изменять объект; в противном случае вы не должны использовать const для параметра, так как вы будете изменять объект.

Если вам когда-либо понадобится использовать const_cast и другой оператор приведения к тому же объекту, используйте const_cast last, поскольку удаление константности из объекта может привести к непреднамеренным изменениям, если вы использовали последующее приведение.

Оператор static_cast полезен для приведения:

  • Типы с плавающей точкой к целочисленным типам (производя усеченный результат)
  • Целочисленные типы для типов с плавающей запятой.
  • Перечислять типы в целочисленные типы.
  • Целочисленные типы для перечислимых типов.
  • Производные классы до базовых классов.
  • Типы для ссылки на производный тип.
  • Указатель производного класса на указатель базового класса.

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

Оператор dynamic_cast полезен для приведения через виртуальное наследование. static_cast может приводить от производного класса к базовому классу, независимо от того, является ли наследование виртуальным или нет. Скажем, однако, вам дан объект типа A, но вы знаете, что на самом деле это объект типа B, и что B наследуется практически от A. Если вы хотите привести этот объект обратно к B, чтобы использовать функции-члены, которые только B обеспечивает, вам нужно использовать dynamic_cast.

Несколько вещей о dynamic_cast. Во-первых, он работает только для преобразования указатель-указатель или ссылка-указатель. Во-вторых, он не может на самом деле привести объект из A к B, если этот объект фактически не является B (или типом, производным от B). Сбой указателя на указатель dynamic_cast возвращает ноль. Ошибка ссылки на ссылку вызывает исключение std::bad_cast .

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

Как мы видели в StorageDurationSample , StorageDurationSample является приведение указателя к целочисленному типу, достаточно большому для его хранения. Это дает адрес памяти указателя, который может быть полезен для операций отладки и трассировки, где вы можете создавать дамп данных в файлы журналов и создавать дампы ядра, но он не может легко запустить отладчик. Вы увидите, что время от времени он используется законно для других целей, но в целом его следует рассматривать как последний акт (за исключением преобразования в стиле C, которое следует после reinterpret_cast).


Приведение в стиле C (например, auto someData = (SomeType)dataOfSomeOtherType; ) не является вашим другом. Вы, несомненно, знакомы с ним из C #, где это очень полезно. В C #, если вы попытаетесь выполнить приведение с использованием этого синтаксиса, и приведение будет недействительным, вы создадите исключение InvalidCastException. Это происходит потому, что CLR отслеживает типы всего, что вы создали, и обнаруживает неудачные броски.

C ++ не проверяет, является ли ваше приведение в стиле C допустимым, при условии, конечно, что оно компилируется. С ++ просто предполагает, что это так. Если это плохой актерский состав, и вам повезло, ваша программа немедленно вылетит. Если нет, вы получите данные в неизвестном состоянии, которые наверняка будут искажены тонкими и коварными способами.

Кроме того, в отличие от других приведений, которые вы можете легко определить, выполнив поиск _cast <, приведения в стиле C не выделяются. При быстром сканировании большого количества кода скобки, заключенные в текст, выглядят так же, как вызов функции, так же как и операция приведения. Вы можете использовать поиск по регулярному выражению для этого в Visual Studio 2012: \ (. * \) [A-Za-z]. Тем не менее, вы по-прежнему отказываетесь от всех преимуществ и защит других каст.

Единственное, что может делать приведение в стиле C, что не может делать другое приведение, — это приведение объекта к одному из его базовых классов защищенного или частного наследования. Вы действительно не должны этого делать, поскольку, если вам нужно публичное наследование, вы должны использовать публичное наследование.

Короче говоря, не используйте броски в стиле C.

Существует пример CastingSample, который демонстрирует множество возможных типов приведения. Он включен в исходный код для этой серии. В целях краткости я опускаю это здесь.

В этой статье мы рассмотрели приведение в C ++, и я надеюсь, что ясно, что вы не должны использовать приведение в стиле C. Следующая статья увеличивает строки в C ++.

Этот урок представляет собой главу из C ++ Succinctly , бесплатной книги от команды Syncfusion .