Как правильно делать броски в этих случаях? dynamic_cast / static_cast [duplicate]

JQuery не может добавлять элементы к (кажется, они добавляют их в DOM-проводник, но не на экран).

Обходным путем является добавление со всеми элементами, которые вам нужны для этой страницы, а затем изменение атрибутов элементов с помощью .attr().

$('body')
  .append($(''))
  .mousemove( function (e) {
      $("#c").attr({
          cx: e.pageX,
          cy: e.pageY
      });
  });

http://jsfiddle.net/8FBjb/1/

2058
задан user3728501 24 August 2015 в 13:58
поделиться

6 ответов

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, состоит в том, что обычно, если вы возвращаете результат обратно к исходному типу, вы получите то же самое значение (но not , если промежуточный тип меньше, чем оригинальный type). Существует ряд преобразований, которые reinterpret_cast также не может сделать. Он используется в первую очередь для особо странных преобразований и манипуляций с битами, таких как превращение потока необработанных данных в фактические данные или хранение данных в младших битах выровненного указателя.


C-style cast and function- стиль cast - это отливки с использованием (type)object или type(object), соответственно. Листинг C-стиля определяется как первое из следующего, которое преуспевает:

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

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

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

2219
ответ дан 22 revs, 16 users 69% 17 August 2018 в 09:26
поделиться
  • 1
    dynamic_cast - только для полиморфных типов. вам нужно использовать его только при переходе к производному классу. static_cast - это, безусловно, первый вариант, если вам не нужна функциональная функция dynamic_cast. Это не какой-то чудотворный серебряный пуля ", проверяющий тип проверки" в целом. – jalf 1 December 2008 в 22:20
  • 2
    Отличный ответ! Одно быстрое замечание: static_cast может потребоваться, чтобы включить иерархию в случае, если у вас есть Derived * & amp; для заливки в Base * & amp ;, поскольку двойные указатели / ссылки не автоматически приводят в действие иерархию. Я столкнулся с такой (откровенно, не обычной) ситуацией две минуты назад. ;-) – bartgol 8 April 2013 в 16:16
  • 3
    * «никакой другой C ++-кастинг не способен удалить const (даже не reinterpret_cast)» ... действительно? Как насчет reinterpret_cast<int *>(reinterpret_cast<uintptr_t>(static_cast<int const *>(0)))? – Mehrdad 15 January 2015 в 12:33
  • 4
    Я думаю, что важная деталь, отсутствующая выше, заключается в том, что dynamic_cast имеет ограничение производительности во время выполнения по сравнению с static или reinterpret_cast. Это важно, например. в режиме реального времени. – jfritz42 30 July 2015 в 00:55
  • 5
    Может быть, стоит упомянуть, что reinterpret_cast часто является оружием выбора при работе с набором непрозрачных типов API – camelCase 4 August 2015 в 13:09

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

Ниже приведены некоторые практические примеры, когда я использовал 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);
}
153
ответ дан CoffeeandCode 17 August 2018 в 09:26
поделиться
  • 1
    Теория некоторых других ответов хороша, но все еще запутанна, видя эти примеры после прочтения других ответов, действительно заставляет их иметь смысл. Это без примеров, я все еще был не уверен, но с ними я теперь уверен, что другие ответы означают. – Solx 29 April 2014 в 15:41
  • 2
    О последнем использовании reinterpret_cast: это не то же самое, что использовать static_cast<char*>(&val)? – Lorenzo Belli 27 May 2016 в 11:55
  • 3
    @LorenzoBelli Конечно нет. Вы попробовали? Последнее недействительно C ++ и блокирует компиляцию. static_cast работает только между типами с определенными преобразованиями, видимым отношением по наследованию или с / от void *. Для всего остального есть и другие броски. reinterpret cast любому типу char * разрешено разрешать чтение представления любого объекта - и один из тех случаев, когда это ключевое слово полезно, а не безудержный генератор реализации / неопределенного поведения. Но это не считается «нормальным» преобразованием, поэтому не допускается (обычно) очень консервативным static_cast. – underscore_d 16 July 2016 в 22:53
  • 4
    reinterpret_cast довольно распространен, когда вы работаете с системным программным обеспечением, таким как базы данных. В большинстве случаев вы пишете собственный менеджер страниц, который не знает, что такое тип данных, хранящийся на странице, и просто возвращает указатель на пустоту. Его вплоть до более высоких уровней, чтобы сделать реинтерпрет литье и сделать вывод, как они хотят. – Sohaib 17 May 2017 в 11:46

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

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

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

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

285
ответ дан herohuyongtao 17 August 2018 в 09:26
поделиться

В дополнение к остальным ответам до сих пор здесь неочевидный пример, где 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 (at цена дополнительной переменной) следующим образом:

#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);
10
ответ дан Lii 17 August 2018 в 09:26
поделиться

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

static_cast

  • Компилятор C ++ уже знает, как преобразовать типы масштабирования, такие как float to int. Используйте static_cast для них.
  • Как правило, при преобразовании типа A в B static_cast будет вызывать конструктор B, передающий его A. Если B не имеет такого конструктора, тогда вы получаете ошибку времени компиляции.
  • Отправлено от A* до B* всегда, если A и B находятся в иерархии наследования (или void), в противном случае вы получите ошибку компиляции.
  • Gotcha: Если вы указали базовый указатель к производному указателю, но если фактический объект есть, если не производный тип, то вы не получите ошибку. Вы получаете плохой указатель, и как только вы пытаетесь получить доступ к элементам производного указателя, вы получаете segfault во время выполнения.
  • То же самое для A& - B&.
  • Gotcha: Бросьте из Derived в Base или наоборот, создайте новую копию!
  • 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 const, он не может идти другим путем. Константа const может работать в обоих направлениях.
      • Одним из примеров, когда это удобно, является итерация через некоторый контейнер, такой как set<T>, который возвращает только его элементы как const, чтобы убедиться, что вы не меняете его ключ. Однако, если ваше намерение состоит в том, чтобы изменить не-ключевые члены объекта, тогда это должно быть хорошо. Вы можете использовать const_cast для удаления константы.
      • Другой пример - это когда вы хотите реализовать T& foo(), а также const T& foo(). Чтобы избежать дублирования кода, вы можете применить const_cast для возврата значения одной функции из другого.

      reinterpret_cast

      • В основном это говорит о том, что берут эти байты в эту память местоположение и подумать об этом как заданный объект.
      • Например, вы можете загрузить 4 байта с плавающей точкой в ​​4 байта int, чтобы увидеть, как выглядят биты в float.
      • Очевидно, если данные неверны для типа, вы можете получить segfault.
      • Для этого приведения нет времени выполнения
53
ответ дан ShitalShah 17 August 2018 в 09:26
поделиться
  • 1
    Последняя точка в const_cast неверна: только dynamic_cast имеет накладные расходы времени исполнения. Кажется, что вы, возможно, переключили порядок и забыли переместить и переписать его. – rubenvb 10 July 2018 в 13:12
  • 2
    Вы правы! Исправлена. – ShitalShah 25 July 2018 в 04:11

Ответил ли этот на ваш вопрос?

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

12
ответ дан talnicolas 17 August 2018 в 09:26
поделиться
  • 1
    Я использовал reinterpret_cast для одной цели - вытащить биты из двойника (такой же размер, как и длинный на моей платформе). – Joshua 14 November 2009 в 23:33
  • 2
    reinterpret_cast необходим, например. для работы с объектами COM. CoCreateInstance () имеет выходной параметр типа void ** (последний параметр), в котором вы передадите свой указатель, объявленный, например. «INetFwPolicy2 * pNetFwPolicy2». Для этого вам нужно написать что-то вроде reinterpret_cast & lt; void ** & gt; (& amp; pNetFwPolicy2). – Serge Rogatch 31 May 2015 в 13:44