Я слышал, что функция static_cast
должна быть предпочтительнее, чем C-стиль или простое литье в стиле функции. Это правда? Зачем?Зачем использовать static_cast <int> (x) вместо (int) x?
ответ
Основная причина заключается в том, что классический С бросает не делает никакого различия между тем, что мы называем static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
и dynamic_cast<>()
. Эти четыре вещи совершенно разные.
A static_cast<>()
обычно безопасен. Существует допустимое преобразование на языке или соответствующий конструктор, который делает это возможным. Единственный раз, когда это немного рискованно, вы бросаете в унаследованный класс; вы должны убедиться, что объект на самом деле является потомком, который, по вашему утверждению, есть, посредством внешнего языка (например, флаг в объекте). A dynamic_cast<>()
является безопасным, пока проверяется результат (указатель) или возможное исключение (ссылка).
A reinterpret_cast<>()
(или const_cast<>()
) с другой стороны всегда опасно. Вы говорите компилятору: «Поверьте мне: я знаю, что это не похоже на foo
(это выглядит так, как будто это не изменчиво), но это«.
Первая проблема заключается в том, что практически невозможно определить, какой из них произойдёт в стиле C-стиле, не глядя на большие и разбросанные фрагменты кода и зная все правила.
Давайте предположим, что они:
class CMyClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
Теперь эти два составляются таким же образом:
CMyClass *pMyObject;
pMyObject = static_cast<CMyClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CMyClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
Однако, давайте посмотрим, это почти идентичный код:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
Как вам можно увидеть, нет простого способа различать две ситуации, не зная много о всех классах в volved.
Вторая проблема заключается в том, что приведение в стиле C слишком сложно найти. В сложных выражениях может быть очень сложно увидеть стили C-стиля. Практически невозможно написать автоматизированный инструмент, в котором необходимо найти приводы C-стиля (например, инструмент поиска) без полномасштабного интерфейса компилятора C++. С другой стороны, легко найти «static_cast <» или «reinterpret_cast <».
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
Это означает, что не только C-стиле бросает более опасным, но это намного труднее найти их все, чтобы убедиться, что они правильны.
static_cast, в стороне от манипулирования указателей на классы, также может быть использована для выполнения преобразований явно определенных в классах, а также для выполнения стандартных преобразований между основными типами:
double d = 3.14159265;
int i = static_cast<int>(d);
static_cast
означает, что вы не можете случайно const_cast
или reinterpret_cast
, что хорошо.
Речь идет о том, сколько типа безопасности вы хотите навязать.
Когда вы пишете (bar) foo
(что эквивалентно reinterpret_cast<bar> foo
, если вы не предоставили оператора преобразования типа), вы говорите компилятору, чтобы игнорировать безопасность типа, и просто делайте, как сказано.
Когда вы пишете static_cast<bar> foo
, вы просите компилятор, по крайней мере, проверить, что преобразование типа имеет смысл и для интегральных типов вставить код преобразования.
EDIT 2014-02-26
Я написал этот ответ более чем 5 лет назад, и я получил это неправильно. (См. Комментарии.) Но он по-прежнему получает upvotes!
Один прагматический совет: вы можете легко искать ключевое слово static_cast в своем исходном коде, если планируете убрать проект.
Вопрос больше, чем просто использовать wither static_cast или C style casting, потому что есть разные вещи, которые случаются при использовании стилей стиля C. Операторы литья C++ предназначены для того, чтобы сделать эти операции более явными.
На поверхности static_cast и стиль C бросает по всей видимости, то же самое, например, при заливке одного значения к другому:
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>(i); //C++ cast
Оба эти ввергнуть целое значение в два раза. Однако при работе с указателями все усложняется. некоторые примеры:
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int(5); //(2) that weird?
char* c1 = static_cast<char*>(new int(5)); //(3) compile time error
В этом примере (1), может быть ОК, так как объект, на который указывает на самом деле является экземпляром B. Но что, если вы не знаете, в этот момент в коде, какой на самом деле указывает на ? (2) может быть совершенно законным (вам нужно только посмотреть на один байт целого числа), но это также может быть ошибкой, и в этом случае ошибка будет приятной, например (3). Операторы литья C++ предназначены для выявления этих проблем в коде, предоставляя ошибки компиляции или времени выполнения, когда это возможно.
Итак, для строгой «кавычки значений» вы можете использовать static_cast. Если вы хотите, чтобы полиморфное литье указателей во время выполнения использовало dynamic_cast. Если вы действительно хотите забыть о типах, вы можете использовать reintrepret_cast. А просто выкинуть const из окна есть const_cast.
Они просто делают код более явным, чтобы он выглядел так, будто вы знаете, что делаете.
C Отливки в стиле легко пропустить в блоке кода. Стили стиля C++ - это не только лучшая практика; они обеспечивают гораздо большую степень гибкости.
reinterpret_cast допускает интегральные преобразования типов указателей, однако может быть опасным, если его неправильно использовать.
static_cast предлагает хорошее преобразование для числовых типов, например. от enum до int или ints до float или любых типов данных, которые вы уверены в типе. Он не выполняет никаких проверок времени выполнения.
dynamic_cast, с другой стороны, выполнит эти проверки, помечая любые неоднозначные назначения или преобразования. Он работает только с указателями и ссылками и несет накладные расходы.
Есть еще пара других, но это основные из них, с которыми вы столкнетесь.
- Позволяет слепки быть легко найден в код с помощью Grep или аналогичных инструментов.
- Указывает, какой вид вы делаете, и помогаете помощь компилятора в его обеспечении. Если вы хотите удалить const-ness, тогда вы можете использовать const_cast, что не позволит вам делать другие типы конверсий.
- Кастеты по своей сути уродливые - вы, как , программист бросает вызов тому, как компилятор обычно обрабатывал ваш код . Вы говорите компилятору : «Я знаю лучше вас». В таком случае, имеет смысл , что выполнение броска должна быть умеренно болезненной вещью, чтобы сделать, и , что они должны торчать в вашем кода, так как они являются вероятным источником проблем.
См Effective C++ Введение
Короче:
static_cast<>()
дает время компиляции возможность проверки, C-Style бросок не делает.static_cast<>()
можно легко обнаружить в любом месте исходного кода на C++; в отличие от этого, C_Style cast сложнее обнаружить.- Намерения передаются гораздо лучше с использованием C++-трансляций.
Подробнее Объяснение:
Статический бросок выполняет преобразование между совместимыми типами. Он похож на C-стиль, но более ограничительный. Например, приведение в стиле C позволит целочисленному указателю указывать на символ.
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
Так как это приводит к 4-байтовой указатель, указывающий на 1 байт, выделенных памяти, запись в этот указатель будет либо вызвать ошибку во время выполнения или перезаписывает некоторые смежную память.
*p = 5; // run-time error: stack corruption
В отличии от литого C-стиль, статический бросок позволит компилятора, чтобы проверить, что типы данных указателя и pointee являются совместимы, что позволяет программисту поймать это неправильное назначение указателя во время компиляции ,
int *q = static_cast<int*>(&c); // compile-time error
Подробнее на:
What is the difference between static_cast<> and C style casting
и
Regular cast vs. static_cast vs. dynamic_cast
Возражение Ваша честь, [спросил и ответил] (http://stackoverflow.com/questions/28002/regular-cast -vs-staticcast-против-dynamiccast). – 2008-09-19 16:36:23
Я не согласен, этот другой вопрос касался описания различий между приведениями в C++. Этот вопрос касается реальной полезности static_cast, который немного отличается. – 2008-09-19 16:40:48
Мы могли бы объединить два вопроса, но то, что нам нужно было бы сохранить из этого потока, - это преимущество использования функций над кастингом C-стиля, которое в настоящее время упоминается только в однострочном ответе в другом потоке, без голосов. – 2008-09-20 08:26:35