Интересно, что это не влияет на словарь или задание понятий.
>>> [x for x in range(1, 10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
9
>>> {x for x in range(1, 5)}
set([1, 2, 3, 4])
>>> x
9
>>> {x:x for x in range(1, 100)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19, 20: 20, 21: 21, 22: 22, 23: 23, 24: 24, 25: 25, 26: 26, 27: 27, 28: 28, 29: 29, 30: 30, 31: 31, 32: 32, 33: 33, 34: 34, 35: 35, 36: 36, 37: 37, 38: 38, 39: 39, 40: 40, 41: 41, 42: 42, 43: 43, 44: 44, 45: 45, 46: 46, 47: 47, 48: 48, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57, 58: 58, 59: 59, 60: 60, 61: 61, 62: 62, 63: 63, 64: 64, 65: 65, 66: 66, 67: 67, 68: 68, 69: 69, 70: 70, 71: 71, 72: 72, 73: 73, 74: 74, 75: 75, 76: 76, 77: 77, 78: 78, 79: 79, 80: 80, 81: 81, 82: 82, 83: 83, 84: 84, 85: 85, 86: 86, 87: 87, 88: 88, 89: 89, 90: 90, 91: 91, 92: 92, 93: 93, 94: 94, 95: 95, 96: 96, 97: 97, 98: 98, 99: 99}
>>> x
9
Однако он был исправлен в 3, как указано выше.
Главная причина состоит в том, что классические броски C не делают различия между тем, что мы называем static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
, и dynamic_cast<>()
. Эти четыре вещи полностью отличаются.
А static_cast<>()
обычно безопасен. Существует допустимое преобразование на языке или соответствующий конструктор, который позволяет. Единственное время это немного опасно, - когда Вы разрушаете к наследованному классу; необходимо удостовериться, что объект является на самом деле потомком, что Вы утверждаете, что это средствами, внешними на язык (как флаг в объекте). dynamic_cast<>()
безопасно, пока результат проверяется (указатель), или возможное исключение принято во внимание (ссылка).
А reinterpret_cast<>()
(или const_cast<>()
), с другой стороны, всегда опасен. Вы говорите компилятор: "доверяйте мне: Я знаю, что это не похоже foo
(это смотрит, как будто это не изменяемо), но это".
первая проблема состоит в том, что почти невозможно сказать, какой произойдет в броске C-стиля, не смотря на большие и рассеянные части кода и зная все правила.
Позволяют нам принять их:
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
Теперь, эти два компилируются тот же путь:
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(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!!!
, Как Вы видите, нет никакого простого способа различать эти две ситуации, не зная много обо всех включенных классах.
вторая проблема состоит в том, что броски 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 ключевое слово в исходном коде, если Вы планируете убрать проект.
static_cast
средства, что Вы не можете случайно const_cast
или reinterpret_cast
, который является хорошей вещью.
static_cast, кроме управления указателями на классы, может также использоваться, чтобы выполнить преобразования, явно определенные в классах, а также выполнить стандартные преобразования между фундаментальными типами:
double d = 3.14159265;
int i = static_cast<int>(d);
Это о том, сколько безопасности типов Вы хотите наложить.
, Когда Вы пишете (bar) foo
(который эквивалентен reinterpret_cast<bar> foo
, если Вы не обеспечили оператор преобразования типов) Вы говорите компилятору игнорировать безопасность типов, и просто делать, как это сказано.
, Когда Вы пишете static_cast<bar> foo
, Вы просите, чтобы компилятор, по крайней мере, проверил, что преобразование типов имеет смысл и, для целочисленных типов, вставлять некоторый код преобразования.
РЕДАКТИРОВАНИЕ 26.02.2014
я записал этот ответ больше чем 5 лет назад, и я понял его превратно. (См. комментарии.), Но это все еще получает upvotes!
См. Эффективный C++ Введение
C броски Стиля легки отсутствовать в блоке кода. Броски стиля C++ не являются только лучшей практикой; они предлагают намного большую степень гибкости.
reinterpret_cast позволяет интеграл преобразованиям типа указателя, однако может быть небезопасным, если неправильно используется.
static_cast предлагает хорошее преобразование для числовых типов, например, от как перечисления к ints или ints к плаваниям или любым типам данных, Вы уверены в типе. Это не выполняет проверок времени выполнения.
dynamic_cast, с другой стороны, выполнит эти проверки, отмечающие любые неоднозначные присвоения или преобразования. Это только работает над указателями и ссылками и подвергается издержкам.
существует несколько других, но это основные, с которыми Вы столкнетесь.
Вопрос больше, чем просто использование иссушает static_cast или кастинг стиля C, потому что существуют разные вещи, которые происходят при использовании 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) возможно, хорошо, потому что объект, на который указывает A, является действительно экземпляром B. Но что, если Вы не знаете в той точке в коде, что на самом деле указывает на? (2) возможно, совершенно законный (Вы только хотите посмотреть на один байт целого числа), но это могла также быть ошибка, в этом случае ошибка, будет хорош, как (3). Операторы кастинга C++ предназначаются для представления этих проблем в коде путем обеспечения времени компиляции или ошибок времени выполнения, если это возможно.
Так, для строгого "значения, бросая" можно использовать static_cast. Если Вы хотите полиморфный кастинг во время выполнения использования указателей dynamic_cast. Если Вы действительно хотите забыть о типах, можно использовать reintrepret_cast. И просто бросить константу из окна существует const_cast.
Они просто делают код более явным так, чтобы было похоже, что Вы знаете то, что Вы делали.