Стандарты C ++ упоминают, что reinterpret_cast
определяется реализацией и не дает никаких гарантий, кроме того, что приведение обратно (с использованием reinterpret_cast
) к исходному типу приведет к тому, что исходное значение будет передано первым.
Приведение в стиле C по крайней мере некоторых типов ведет себя примерно одинаково — приведение результатов вперед и назад с одинаковым значением — В настоящее время я работаю с перечислениями и int
с, но есть и другие примеры.
В то время как стандарт C ++ дает эти определения для обоих стилей приведения, дает ли он одинаковую гарантию для смешанных приведений? Если библиотека X возвращается из функции int Y()
немного enum
значение, может использовать любое из приведенных выше приведений, не беспокоясь о том, какое приведение использовалось для преобразования исходного enum
в int
в теле Y? У меня нет исходного кода X, поэтому я не могу проверить (и в любом случае он может измениться в следующей версии), и подобные вещи почти не упоминаются в документации.
Я знаю, что при большинстве реализаций в таких случаях оба приведения ведут себя одинаково; Мой вопрос: что стандарт C ++ говорит о таких случаях — если вообще что-нибудь.
C ++ определяет семантику синтаксиса C cast в терминах static_cast
, const_cast
а также reinterpret_cast
, Таким образом, вы получаете одинаковую гарантию для той же операции, независимо от того, какой синтаксис вы используете для ее достижения.
reinterpret_cast
может использоваться только для конкретных преобразований:
плюс (условно) указатель функции на указатель объекта и наоборот. В большинстве случаев преобразованное значение не указано, но есть гарантия, что преобразование, за которым следует его обратное, даст исходное значение.
В частности, вы не можете использовать reinterpret_cast
конвертировать между целочисленными и перечисляемыми типами; преобразование должно быть сделано с использованием static_cast
(или неявно, при преобразовании перечисления с незаданной областью в целочисленный тип), который хорошо определен для достаточно больших целочисленных типов. Единственная возможная проблема в том, что библиотека сделала что-то совершенно безумное, такое как return reinterpret_cast<int&>(some_enum);
Приведение в стиле C выполнит либо static_cast
или reinterpret_cast
с последующим const_cast
, как необходимо; поэтому любое преобразование, которое четко определяется static_cast
также хорошо определяется броском в стиле C.
Нет, reinterpret_cast
является не эквивалентно броску стиля C. Броски в стиле C позволяют отбрасывать постоянные переменные (поэтому они включают const_cast
) не допускается в reinterpret_cast
, Если static_cast
допускается между типами источника и назначения, он будет выполнять static_cast
который имеет другую семантику, чем reinterpret_cast
, Если преобразование не разрешено, оно будет reinterpret_cast
, Наконец, есть угловой случай, когда приведение C не может быть представлено в терминах любого другого преобразования: оно игнорирует спецификаторы доступа.
Некоторые примеры, которые иллюстрируют различия:
class b0 { int a; };
class b1 { int b; };
class b2 { int c; };
class d : public b0, public b1, b2 {};
int main() {
d x;
assert( static_cast<b1*>(&x) == (b1*)&x );
assert( reinterpret_cast<b1*>(&x) != (b1*)&x ); // Different value
assert( reinterpret_cast<b2*>(&x) != (b2*)&x ); // Different value,
// cannot be done with static_cast
const d *p = &x;
// reinterpret_cast<b0*>(p); // Error cannot cast const away
(b0*)p; // C style can
}