Когда следует использовать static_cast, dynamic_cast, const_cast и reinterpret_cast?

Как правильно использовать:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • Литой в стиле C (type)value
  • Приведение в функциональном стиле type(value)

Как решить, что использовать в конкретных случаях?

Для некоторых полезных конкретных примеров использования различных типов приведений вы можете проверить первый ответ на аналогичный вопрос в эта другая тема.

TeaMonkie 24.02.2017 13:41

Вы можете найти действительно хорошие ответы на свой вопрос выше. Но я хотел бы поставить здесь еще один момент: @ e.James: «Нет ничего, что могли бы сделать эти новые операторы преобразования в C++, а преобразование в стиле C не могут.

BreakBadSP 09.10.2018 10:51

@BreakBadSP Новые преобразования имеют тип нет только для лучшей читаемости кода. Они созданы для того, чтобы усложнить выполнение опасных вещей, таких как отбрасывание констант или приведение указателей вместо их значений. static_cast имеет гораздо меньше возможностей сделать что-то опасное, чем приведение в стиле c!

FourtyTwo 13.01.2020 15:50

@FourtyTwo согласился

BreakBadSP 16.01.2020 11:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2 672
5
598 566
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

это отвечает на ваш вопрос?

Я никогда не использовал reinterpret_cast и задаюсь вопросом, не пахнет ли чехол, который в нем нуждается, плохим дизайном. В кодовой базе, которую я работаю, много используется dynamic_cast. Разница с static_cast заключается в том, что dynamic_cast выполняет проверку во время выполнения, которая может (безопаснее) или не может (больше накладных расходов) быть тем, что вы хотите (см. msdn).

Я использовал reinterpret_cast с одной целью - получить биты из двойника (того же размера, что и на моей платформе).

Joshua 15.11.2009 01:33

reinterpret_cast требуется, например для работы с COM-объектами. CoCreateInstance () имеет выходной параметр типа void ** (последний параметр), в котором вы передадите свой указатель, объявленный, например, как «INetFwPolicy2 * pNetFwPolicy2». Для этого вам нужно написать что-то вроде reinterpret_cast <void **> (& pNetFwPolicy2).

Serge Rogatch 31.05.2015 16:44

Возможно, есть другой подход, но я использую reinterpret_cast для извлечения фрагментов данных из массива. Например, если у меня есть char*, содержащий большой буфер, полный упакованных двоичных данных, которые мне нужно пройти и получить отдельные примитивы разных типов. Примерно так: template<class ValType> unsigned int readValFromAddress(char* addr, ValType& val) { /*On platforms other than x86(_64) this could do unaligned reads, which could be bad*/ val = (*(reinterpret_cast<ValType*>(addr))); return sizeof(ValType); }

James Matta 23.08.2018 22:34

Я никогда не использовал reinterpret_cast, его не так много применений.

Pika the Master of the Whales 13.10.2018 19:31

Лично я видел использование reinterpret_cast только по одной причине. Я видел необработанные данные объекта, хранящиеся в базе данных типа данных «blob», а затем, когда данные извлекаются из базы данных, reinterpret_cast используется для преобразования этих необработанных данных в объект.

ImaginaryHuman072889 07.10.2019 14:29

Отсутствие комментариев к reinterpret_cast говорит о многом. Если ваш C++ использует другую библиотеку C, потом, вы увидите много reinterpret_cast.

eigenfield 14.08.2020 06:54

Используйте dynamic_cast для преобразования указателей / ссылок в иерархии наследования.

Используйте static_cast для преобразования обычных типов.

Используйте reinterpret_cast для низкоуровневой переинтерпретации битовых шаблонов. Используйте с особой осторожностью.

Используйте const_cast для отбрасывания const/volatile. Избегайте этого, если вы не застряли в использовании API, неверного по константе.

Будьте осторожны с dynamic_cast. Он полагается на RTTI, и это не будет работать должным образом за пределами общих библиотек. Просто потому, что вы создаете исполняемые и разделяемые библиотеки независимо друг от друга, не существует стандартизованного способа синхронизации RTTI между разными сборками. По этой причине в библиотеке Qt существует qobject_cast <>, который использует информацию о типе QObject для проверки типов.

user3150128 23.10.2018 11:25
Ответ принят как подходящий

static_cast - это первое приведение, которое вы должны попытаться использовать. Он выполняет такие вещи, как неявные преобразования между типами (например, int в float или указатель на void*), а также может вызывать функции явного преобразования (или неявные). Во многих случаях явно указывать static_cast не обязательно, но важно отметить, что синтаксис T(something) эквивалентен (T)something, и его следует избегать (подробнее об этом позже). Однако T(something, something_else) безопасен и гарантированно вызывает конструктор.

static_cast также может проходить через иерархии наследования. В этом нет необходимости при приведении вверх (к базовому классу), но при приведении вниз его можно использовать, если оно не выполняется через наследование virtual. Однако он не выполняет проверку, и это неопределенное поведение для static_cast вниз по иерархии до типа, который на самом деле не является типом объекта.


const_cast может использоваться для удаления или добавления const к переменной; никакое другое приведение C++ не способно удалить его (даже reinterpret_cast). Важно отметить, что изменение ранее существовавшего значения const не определено только в том случае, если исходной переменной является const; если вы используете его, чтобы убрать ссылку на const на то, что не было объявлено с const, это безопасно. Это может быть полезно, например, при перегрузке функций-членов на основе const. Его также можно использовать для добавления const к объекту, например для вызова перегрузки функции-члена.

const_cast также работает аналогично с volatile, хотя это встречается реже.


dynamic_cast используется исключительно для обработки полиморфизма. Вы можете привести указатель или ссылку на любой полиморфный тип к любому другому типу класса (полиморфный тип имеет по крайней мере одну виртуальную функцию, объявленную или унаследованную). Вы можете использовать его не только для заброса вниз - вы можете забрасывать его боком или даже вверх по другой цепи. dynamic_cast найдет желаемый объект и, если возможно, вернет его. Если не может, он вернет nullptr в случае указателя или выбросит std::bad_cast в случае ссылки.

Однако dynamic_cast имеет некоторые ограничения. Это не работает, если в иерархии наследования есть несколько объектов одного типа (так называемый «ужасный ромб») и вы не используете наследование virtual. Он также может пройти только через публичное наследование - он всегда не сможет пройти через наследование protected или private. Однако это редко является проблемой, поскольку такие формы наследования редки.


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


C-стиль гипс и приведение в функциональном стиле представляют собой приведения с использованием (type)object или type(object), соответственно, и функционально эквивалентны. Они определяются как первые из следующих успешных:

  • const_cast
  • static_cast (правда, игнорируя ограничения доступа)
  • static_cast (см. Выше), затем const_cast
  • reinterpret_cast
  • reinterpret_cast, затем const_cast

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

Приведения в стиле C также игнорируют управление доступом при выполнении static_cast, что означает, что они имеют возможность выполнять операцию, которую не может выполнить ни одно другое приведение. Тем не менее, это в основном кладж, и, на мой взгляд, это еще одна причина избегать приведений в стиле C.

Я бы порекомендовал в качестве первого варианта dynamic_cast <>, который, конечно, работает только так, как описано выше. Всякий раз, когда вы можете выполнить dynamic_cast <>, он будет проверять, действительно ли тип соответствует вашему мнению.

David Rodríguez - dribeas 02.12.2008 00:02

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

jalf 02.12.2008 00:20

В разделе reinterpret_cast показано нарушение псевдонима и, следовательно, неопределенное поведение. Если вам нужно такое преобразование типов, лучше всего это сделать с помощью memcpy.

bames53 03.03.2013 21:02

Отличный ответ! Одно быстрое замечание: static_cast может потребоваться для преобразования иерархии в случае, если у вас есть Derived * & для преобразования в Base * &, поскольку двойные указатели / ссылки не создают автоматически иерархию. С такой (честно говоря, не типичной) ситуацией я столкнулся две минуты назад. ;-)

bartgol 08.04.2013 19:16

Определяется ли поведение использования const_cast для указателя? Скажем, у меня есть std::string s("hi"); auto p = s.c_str();, а p - это const char*. Выполняет ли const_cast<char*>(p) = "hello"; определенное поведение?

0x499602D2 03.07.2013 20:45

в главе 22 «Язык программирования C++» более подробно описаны const_cast и dynamic_cast. @ unj2

Maadiah 21.01.2014 12:30

@ unj2 Аннотации C++: icce.rug.nl/documents/cplusplus/cplusplus03.html#an241

Herbert 16.09.2014 15:31

* "никакое другое преобразование C++ не способно удалить const (даже reinterpret_cast)" ... правда? А как насчет reinterpret_cast<int *>(reinterpret_cast<uintptr_t>(static_cast<int const *>(0)))?

user541686 15.01.2015 14:33

Я думаю, что важная деталь, отсутствующая выше, заключается в том, что dynamic_cast снижает производительность во время выполнения по сравнению со static или reinterpret_cast. Это важно, например, в программном обеспечении в реальном времени.

jfritz42 30.07.2015 03:55

Возможно, стоит упомянуть, что reinterpret_cast часто является предпочтительным оружием при работе с набором непрозрачных типов данных API.

Class Skeleton 04.08.2015 16:09

Думаю, следует отметить, что динамический состав работает только при включенном информация о типе времени выполнения. Кажется, это по умолчанию для всех основных компиляторов.

Lii 04.01.2016 23:11

«Это, в основном, кладж, и, на мой взгляд, это еще одна причина, по которой следует избегать приведений в стиле C.» Похоже, вы говорите, что нет ситуаций, когда приведение в стиле C. Итак, что бы вы сказали о следующем примере: stackoverflow.com/q/38682050/2725810?

AlwaysLearning 31.07.2016 12:15

Почему dynamic_cast «почти исключительно» используется для полиморфизма? Есть ли ситуация, когда dynamic_cast подходит для чего-то другого, кроме полиморфизма?

Opux 28.03.2017 21:50

Этот ответ не объясняет, что делает приведение в функциональном стиле. Это можно было добавить?

Quuxplusone 14.08.2017 22:42

В дополнение к примечанию с информацией о типе времени выполнения, еще одно важное замечание: dynamic_cast правильно работает только с объектами с vtables. Другими словами, в производном классе должна быть хотя бы одна виртуальная функция.

Adrian 12.11.2018 23:58

@Mehrdad: эффект обратного преобразования к типу указателя разные определяется реализацией.

Davis Herring 23.06.2019 02:42

А как насчет std::any_cast? Может ли кто-нибудь объяснить разницу в методах, описанных здесь. Это только для объектов типа std::any?

Patrick 24.01.2020 19:34
static_cast может выполнять неявные преобразования, преобразование указателей с помощью void* и преобразование вверх / вниз в иерархии классов, обратите внимание на 3-й случай, он также хорошо работает с множественным наследованием, что означает, что он может смещать адрес при преобразовании между указателями на объект и подобъект
baye 03.07.2020 18:59

Я обнаружил удивительный (раздражающий) C++ характерная черта, т.е. downcast может происходить только через публичные наследования. Теперь я рассматриваю приведение в стиле C как возможное обходное решение.

peterh 03.08.2020 15:20

(Выше было дано много теоретических и концептуальных объяснений)

Ниже приведены некоторые из практические примеры, когда я использовал static_cast, dynamic_cast, const_cast, reinterpret_cast.

(Также ссылается на это, чтобы понять объяснение: http://www.cplusplus.com/doc/tutorial/typecasting/)

static_cast:

OnEventData(void* pData)

{
  ......

  //  pData is a void* pData, 

  //  EventData is a structure e.g. 
  //  typedef struct _EventData {
  //  std::string id;
  //  std:: string remote_id;
  //  } EventData;

  // On Some Situation a void pointer *pData
  // has been static_casted as 
  // EventData* pointer 

  EventData *evtdata = static_cast<EventData*>(pData);
  .....
}

dynamic_cast:

void DebugLog::OnMessage(Message *msg)
{
    static DebugMsgData *debug;
    static XYZMsgData *xyz;

    if (debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
        // debug message
    }
    else if (xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
        // xyz message
    }
    else/* if ( ... )*/{
        // ...
    }
}

const_cast:

// *Passwd declared as a const

const unsigned char *Passwd


// on some situation it require to remove its constness

const_cast<unsigned char*>(Passwd)

reinterpret_cast:

typedef unsigned short uint16;

// Read Bytes returns that 2 bytes got read. 

bool ByteBuffer::ReadUInt16(uint16& val) {
  return ReadBytes(reinterpret_cast<char*>(&val), 2);
}

Теория некоторых других ответов хороша, но все же сбивает с толку: просмотр этих примеров после прочтения других ответов действительно делает их все понятными. То есть без примеров я все еще не был уверен, но с ними я теперь уверен в том, что означают другие ответы.

Solx 29.04.2014 18:41

О последнем использовании reinterpret_cast: разве это не то же самое, что и использование static_cast<char*>(&val)?

Lorenzo Belli 27.05.2016 14:55

@LorenzoBelli Конечно, нет. Вы пробовали? Последний не является допустимым C++ и блокирует компиляцию. static_cast работает только между типами с определенными преобразованиями, видимыми отношениями по наследству или в / из void *. Для всего остального есть другие составы. reinterpret cast для любого типа char * разрешено читать представление любого объекта - и это единственный случай, когда это ключевое слово полезно, а не безудержный генератор поведения реализации / неопределенности. Но это не считается «нормальным» преобразованием, поэтому не допускается (обычно) очень консервативным static_cast.

underscore_d 17.07.2016 01:53

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

Sohaib 17.05.2017 14:46

Первый пример опасен тем, что предполагает хорошее поведение со стороны вызывающего (всегда передавать указатель на реальный объект EventData и ничего больше). К сожалению, я не думаю, что есть какой-либо практический способ сколько-нибудь значимо проверить тип указателя на пустоту. В идеале аргумент должен быть строго типизированным. Просто некоторые наблюдения; не критика ответа.

Brian A. Henning 29.01.2019 18:29

@ BrianA.Henning Согласен. Я бы лично использовал reinterpret_cast<> в этой ситуации как «красный флаг», чтобы подчеркнуть ваше наблюдение, что вызывающая сторона несет большую ответственность за передачу «действительного» указателя.

franji1 10.01.2020 18:40

@JohannGerell ваше утверждение неверно. Приведенный выше фрагмент на const_cast не имеет доказательств, вызывающих неопределенное поведение. Неопределенное поведение может быть вызвано наличием оператора, изменяющего значение. Использование const_cast для удаления constness допустимо, законно и нормально.

eigenfield 14.08.2020 06:43

@truthadjustr, вы правы, как объясняется в разделе Ноты документа en.cppreference.com/w/cpp/language/const_cast. Я удалил свой комментарий.

Johann Gerell 22.08.2020 14:24

В дополнение к другим ответам, приведенным на данный момент, вот неочевидный пример, когда static_cast недостаточно, поэтому необходим reinterpret_cast. Предположим, есть функция, которая в выходном параметре возвращает указатели на объекты разных классов (которые не имеют общего базового класса). Реальный пример такой функции - CoCreateInstance() (см. Последний параметр, которым на самом деле является void**). Предположим, вы запрашиваете у этой функции конкретный класс объекта, поэтому вы заранее знаете тип указателя (что вы часто делаете для COM-объектов). В этом случае вы не можете преобразовать указатель на ваш указатель в void** с помощью static_cast: вам нужен reinterpret_cast<void**>(&yourPointer).

В коде:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    //static_cast<void**>(&pNetFwPolicy2) would give a compile error
    reinterpret_cast<void**>(&pNetFwPolicy2) );

Однако static_cast работает с простыми указателями (а не с указателями на указатели), поэтому приведенный выше код можно переписать, чтобы избежать использования reinterpret_cast (за счет дополнительной переменной), следующим образом:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    &tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);

Разве не сработало бы что-то вроде &static_cast<void*>(pNetFwPolicy2) вместо static_cast<void**>(&pNetFwPolicy2)?

jp48 14.08.2019 20:26

Это может помочь, если вы немного разбираетесь во внутреннем устройстве ...

static_cast

  • Компилятор C++ уже знает, как преобразовывать между типами масштабирования, такими как float, в int. Используйте для них static_cast.
  • Когда вы просите компилятор преобразовать тип A в B, static_cast вызывает конструктор B, передавая A в качестве параметра. В качестве альтернативы, A может иметь оператор преобразования (например, A::operator B()). Если B не имеет такого конструктора или A не имеет оператора преобразования, вы получите ошибку времени компиляции.
  • Приведение из A* в B* всегда успешно, если A и B находятся в иерархии наследования (или недействительны), в противном случае вы получите ошибку компиляции.
  • Попался: если вы приведете базовый указатель к производному указателю, но если фактический объект действительно не является производным типом, вы получите ошибку не. Вы получаете плохой указатель и, скорее всего, ошибку сегментации во время выполнения. То же самое касается A& - B&.
  • Попался: преобразование из производного в базовое или наоборот создает копию новый! Для людей, пришедших с C# / Java, это может быть огромным сюрпризом, потому что в результате получается обрезанный объект, созданный из Derived.

dynamic_cast

  • dynamic_cast использует информацию о типе времени выполнения, чтобы выяснить, допустимо ли приведение. Например, переход от (Base*) к (Derived*) может завершиться ошибкой, если указатель на самом деле не является производным типом.
  • Это означает, что dynamic_cast очень дорого по сравнению со static_cast!
  • Для A* в B*, если приведение недопустимо, то dynamic_cast вернет nullptr.
  • Для A& в B&, если приведение недопустимо, то dynamic_cast вызовет исключение bad_cast.
  • В отличие от других приведений, это накладные расходы времени выполнения.

const_cast

  • Хотя static_cast может преобразовывать неконстантные значения в константу, иначе не может быть. Const_cast может работать обоими способами.
  • Один из примеров, когда это удобно, - это итерация через некоторый контейнер, такой как set<T>, который возвращает только свои элементы как const, чтобы убедиться, что вы не изменили его ключ. Однако, если вы намереваетесь изменить неключевые элементы объекта, все должно быть в порядке. Вы можете использовать const_cast для удаления константности.
  • Другой пример - когда вы хотите реализовать T& SomeClass::foo(), а также const T& SomeClass::foo() const. Чтобы избежать дублирования кода, вы можете применить const_cast для возврата значения одной функции из другой.

reinterpret_cast

  • Это в основном говорит о том, что берите эти байты в этой ячейке памяти и воспринимайте их как заданный объект.
  • Например, вы можете загрузить 4 байта float в 4 байта int, чтобы увидеть, как выглядят биты в float.
  • Очевидно, что если данные не соответствуют типу, вы можете получить segfault.
  • Это приведение не требует дополнительных затрат времени выполнения.

Я добавил информацию об операторе преобразования, но есть еще несколько вещей, которые также следует исправить, и я не чувствую себя комфортно обновлять это слишком часто. Пункты следующие: 1. If you cast base pointer to derived pointer but if actual object is not really derived type then you don't get error. You get bad pointer and segfault at runtime. Вы получаете UB, что может привести к сбою во время выполнения, если вам повезет. 2. Динамические забросы также можно использовать при перекрестном забросе. 3. Константное приведение в некоторых случаях может привести к UB. Использование mutable может быть лучшим выбором для реализации логической константности.

Adrian 12.11.2018 23:33

@ Адриан, ты прав во всех отношениях. Ответ написан для людей более или менее начального уровня, и я не хотел перегружать их всеми другими сложностями, связанными с mutable, кросс-кастингом и т. д.

Shital Shah 16.11.2018 14:20

Хотя в других ответах хорошо описаны все различия между приведениями C++, я хотел бы добавить короткое замечание, почему вы не должны использовать приведения в стиле C (Type) var и Type(var).

Для новичков в C++ приведение типов в стиле C выглядит как надстройка над приведением типов в C++ (static_cast <> (), dynamic_cast <> (), const_cast <> (), reinterpret_cast <> ()), и кто-то может предпочесть их приведению C++. . Фактически, приведение в стиле C - это надмножество, и писать его короче.

Основная проблема приведений в стиле C заключается в том, что они скрывают истинное намерение разработчика приведения типов. Приведения в стиле C могут выполнять практически все типы приведения, от обычно безопасных приведения, выполняемых static_cast <> () и dynamic_cast <> (), до потенциально опасных типов, таких как const_cast <> (), где модификатор const может быть удален, чтобы переменные const можно изменить и переинтерпретировать_каст <> (), который даже может переинтерпретировать целочисленные значения в указатели.

Вот образец.

int a=rand(); // Random number.

int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.

int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.

int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.

*pa4=5; // Program crashes.

Основная причина, по которой в язык были добавлены преобразования C++, заключалась в том, чтобы позволить разработчику прояснить свои намерения - почему он собирается выполнять это преобразование. Используя приведение типов в стиле C, которые вполне допустимы в C++, вы делаете свой код менее читаемым и более подверженным ошибкам, особенно для других разработчиков, которые не создавали ваш код. Таким образом, чтобы сделать ваш код более читаемым и явным, вы всегда должны предпочесть приведение типов C++, а не приведение типов C.

Вот короткая цитата из книги Бьярна Страуструпа (автора C++) The C++ Programming Language 4th edition - page 302.

This C-style cast is far more dangerous than the named conversion operators because the notation is harder to spot in a large program and the kind of conversion intended by the programmer is not explicit.

Голосование за то, что ссылается на цитату Страуструпа. Трудно найти в наши дни, особенно то, что мы часто вместо этого слышали это от людей очень умно, а не от самого человека.

eigenfield 14.08.2020 07:02

Чтобы понять это, давайте рассмотрим нижеприведенный фрагмент кода:

struct Foo{};
struct Bar{};

int main(int argc, char** argv)
{
    Foo* f = new Foo;

    Bar* b1 = f;                              // (1)
    Bar* b2 = static_cast<Bar*>(f);           // (2)
    Bar* b3 = dynamic_cast<Bar*>(f);          // (3)
    Bar* b4 = reinterpret_cast<Bar*>(f);      // (4)
    Bar* b5 = const_cast<Bar*>(f);            // (5)

    return 0;
}

Только строка (4) компилируется без ошибок. Только reinterpret_cast можно использовать для преобразования указателя на объект в указатель на любой несвязанный тип объекта.

Следует отметить следующее: dynamic_cast не сработает во время выполнения, однако на большинстве компиляторов он также не сможет скомпилироваться, потому что в структуре приводимого указателя нет виртуальных функций, что означает, что dynamic_cast будет работать только с указателями полиморфных классов. .

Когда использовать приведение C++:

  • Используйте static_cast как эквивалент приведения в стиле C, который выполняет преобразование значений, или когда нам нужно явно преобразовать указатель от класса к его суперклассу.
  • Используйте const_cast, чтобы удалить квалификатор const.
  • Используйте reinterpret_cast для небезопасного преобразования типов указателей в целочисленные и другие типы указателей и обратно. Используйте это, только если мы знаем, что делаем, и понимаем проблемы сглаживания.

Предоставленный фрагмент - плохой пример. Хотя я согласен, что, действительно, компилируется. Список Когда является неопределенно правильным, но в основном наполнен мнениями, недостаточными для понимания требуемой детализации.

eigenfield 14.08.2020 07:13

Другие вопросы по теме