2008-09-19 1 views
486

Я слышал, что функция static_cast должна быть предпочтительнее, чем C-стиль или простое литье в стиле функции. Это правда? Зачем?Зачем использовать static_cast <int> (x) вместо (int) x?

+25

Возражение Ваша честь, [спросил и ответил] (http://stackoverflow.com/questions/28002/regular-cast -vs-staticcast-против-dynamiccast). – 2008-09-19 16:36:23

+15

Я не согласен, этот другой вопрос касался описания различий между приведениями в C++. Этот вопрос касается реальной полезности static_cast, который немного отличается. – 2008-09-19 16:40:48

+2

Мы могли бы объединить два вопроса, но то, что нам нужно было бы сохранить из этого потока, - это преимущество использования функций над кастингом C-стиля, которое в настоящее время упоминается только в однострочном ответе в другом потоке, без голосов. – 2008-09-20 08:26:35

ответ

495

Основная причина заключается в том, что классический С бросает не делает никакого различия между тем, что мы называем 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-стиле бросает более опасным, но это намного труднее найти их все, чтобы убедиться, что они правильны.

3

static_cast, в стороне от манипулирования указателей на классы, также может быть использована для выполнения преобразований явно определенных в классах, а также для выполнения стандартных преобразований между основными типами:

double d = 3.14159265; 
int i = static_cast<int>(d); 
21

static_cast означает, что вы не можете случайно const_cast или reinterpret_cast, что хорошо.

7

Речь идет о том, сколько типа безопасности вы хотите навязать.

Когда вы пишете (bar) foo (что эквивалентно reinterpret_cast<bar> foo, если вы не предоставили оператора преобразования типа), вы говорите компилятору, чтобы игнорировать безопасность типа, и просто делайте, как сказано.

Когда вы пишете static_cast<bar> foo, вы просите компилятор, по крайней мере, проверить, что преобразование типа имеет смысл и для интегральных типов вставить код преобразования.


EDIT 2014-02-26

Я написал этот ответ более чем 5 лет назад, и я получил это неправильно. (См. Комментарии.) Но он по-прежнему получает upvotes!

94

Один прагматический совет: вы можете легко искать ключевое слово static_cast в своем исходном коде, если планируете убрать проект.

26

Вопрос больше, чем просто использовать 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.

Они просто делают код более явным, чтобы он выглядел так, будто вы знаете, что делаете.

4

C Отливки в стиле легко пропустить в блоке кода. Стили стиля C++ - это не только лучшая практика; они обеспечивают гораздо большую степень гибкости.

reinterpret_cast допускает интегральные преобразования типов указателей, однако может быть опасным, если его неправильно использовать.

static_cast предлагает хорошее преобразование для числовых типов, например. от enum до int или ints до float или любых типов данных, которые вы уверены в типе. Он не выполняет никаких проверок времени выполнения.

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

Есть еще пара других, но это основные из них, с которыми вы столкнетесь.

7
  1. Позволяет слепки быть легко найден в код с помощью Grep или аналогичных инструментов.
  2. Указывает, какой вид вы делаете, и помогаете помощь компилятора в его обеспечении. Если вы хотите удалить const-ness, тогда вы можете использовать const_cast, что не позволит вам делать другие типы конверсий.
  3. Кастеты по своей сути уродливые - вы, как , программист бросает вызов тому, как компилятор обычно обрабатывал ваш код . Вы говорите компилятору : «Я знаю лучше вас». В таком случае, имеет смысл , что выполнение броска должна быть умеренно болезненной вещью, чтобы сделать, и , что они должны торчать в вашем кода, так как они являются вероятным источником проблем.

См Effective C++ Введение

48

Короче:

  1. static_cast<>() дает время компиляции возможность проверки, C-Style бросок не делает.
  2. static_cast<>() можно легко обнаружить в любом месте исходного кода на C++; в отличие от этого, C_Style cast сложнее обнаружить.
  3. Намерения передаются гораздо лучше с использованием 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

 Смежные вопросы

  • Нет связанных вопросов^_^