Por que usar static_cast (x) em vez de (int) x?

Ouvi dizer que a function static_cast deve ser preferida ao estilo C ou à conversão de estilo de function simples. Isso é verdade? Por quê?

A razão principal é que os lançamentos clássicos de C não fazem distinção entre o que chamamos de static_cast<>() , reinterpret_cast<>() , const_cast<>() e dynamic_cast<>() . Essas quatro coisas são completamente diferentes.

Um static_cast<>() é geralmente seguro. Existe uma conversão válida na linguagem ou um construtor apropriado que torna isso possível. A única vez que é um pouco arriscado é quando você recua para uma class herdada; você deve se certificar de que o object é realmente o descendente que você diz ser, por meio externo à linguagem (como uma bandeira no object). Um dynamic_cast<>() é seguro desde que o resultado seja verificado (ponteiro) ou uma possível exceção seja levada em conta (referência).

Um reinterpret_cast<>() (ou um const_cast<>() ) por outro lado é sempre perigoso. Você diz ao compilador: “Confie em mim: eu sei que isso não parece um foo (parece que não é mutável), mas é”.

O primeiro problema é que é quase impossível dizer qual deles ocorrerá em um casting de estilo C sem olhar para pedaços grandes e dispersos de código e conhecer todas as regras.

Vamos supor estes:

 class CMyClass : public CMyBase {...}; class CMyOtherStuff {...} ; CMyBase *pSomething; // filled somewhere 

Agora, esses dois são compilados da mesma maneira:

 CMyClass *pMyObject; pMyObject = static_cast(pSomething); // Safe; as long as we checked pMyObject = (CMyClass*)(pSomething); // Same as static_cast<> // Safe; as long as we checked // but harder to read 

No entanto, vamos ver este código quase idêntico:

 CMyOtherStuff *pOther; pOther = static_cast(pSomething); // Compiler error: Can't convert pOther = (CMyOtherStuff*)(pSomething); // No compiler error. // Same as reinterpret_cast<> // and it's wrong!!! 

Como você pode ver, não há uma maneira fácil de distinguir entre as duas situações sem saber muito sobre todas as classs envolvidas.

O segundo problema é que os modelos do tipo C são difíceis de localizar. Em expressões complexas, pode ser muito difícil ver modelos em estilo C. É praticamente impossível escrever uma ferramenta automatizada que precise localizar conversões no estilo C (por exemplo, uma ferramenta de pesquisa) sem um front-end de compilador C ++ completo. Por outro lado, é fácil procurar “static_cast < " ou "reinterpret_cast <".

 pOther = reinterpret_cast(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. 

Isso significa que, não só o estilo C é mais perigoso, mas é muito mais difícil encontrá-los para garantir que estejam corretos.

Uma dica pragmática: você pode pesquisar facilmente a palavra-chave static_cast no seu código-fonte, caso planeje arrumar o projeto.

Resumindo :

  1. static_cast<>() dá a você uma habilidade de verificação de tempo de compilation, o estilo C não faz.
  2. static_cast<>() pode ser visto facilmente em qualquer lugar dentro de um código-fonte C ++; Em contraste, o casting C_Style é mais difícil de detectar.
  3. Intenções são transmitidas muito melhor usando castings em C ++.

Mais Explicação :

O casting estático realiza conversões entre tipos compatíveis . É semelhante ao modelo de estilo C, mas é mais restritivo. Por exemplo, o conversão de estilo C permitiria que um ponteiro inteiro apontasse para um caractere.

 char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes 

Como isso resulta em um ponteiro de 4 bytes apontando para 1 byte de memory alocada, a gravação nesse ponteiro causará um erro de tempo de execução ou replaceá alguma memory adjacente.

 *p = 5; // run-time error: stack corruption 

Em contraste com a conversão de estilo C, a conversão estática permitirá que o compilador verifique se os tipos de dados de ponteiro e ponteiro são compatíveis, o que permite que o programador capture essa atribuição incorreta de ponteiro durante a compilation.

 int *q = static_cast(&c); // compile-time error 

Leia mais em:
Qual é a diferença entre casting de estilo static_cast <> e C?
e
Elenco regular vs. static_cast vs. dynamic_cast

A questão é maior do que apenas usando wither static_cast ou casting de estilo C porque existem coisas diferentes que acontecem ao usar o estilo C. Os operadores de conversão de C ++ destinam-se a tornar essas operações mais explícitas.

Na superfície static_cast e os estilos de C são exibidos da mesma forma, por exemplo, ao transmitir um valor para outro:

 int i; double d = (double)i; //C-style cast double d2 = static_cast( i ); //C++ cast 

Ambos lançam o valor inteiro para um duplo. No entanto, quando se trabalha com pointers, as coisas ficam mais complicadas. alguns exemplos:

 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( new int( 5 ) ); //(3) compile time error 

Neste exemplo (1) talvez OK, porque o object apontado por A é realmente uma instância de B. Mas e se você não souber, naquele ponto do código, o que realmente aponta? (2) talvez perfeitamente legal (você só quer olhar para um byte do inteiro), mas também poderia ser um erro, caso em que um erro seria bom, como (3). Os operadores de conversão de C ++ destinam-se a expor esses problemas no código, fornecendo erros em tempo de compilation ou em tempo de execução, quando possível.

Então, para “casting de valor” estrito, você pode usar static_cast. Se você quiser a conversão de pointers polimórficos em tempo de execução, use dynamic_cast. Se você realmente quiser esquecer os tipos, use reintrepret_cast. E para apenas jogar const para fora da janela há const_cast.

Eles apenas tornam o código mais explícito para que pareça que você sabe o que estava fazendo.

static_cast significa que você não pode acidentalmente const_cast ou reinterpret_cast , o que é uma coisa boa.

  1. Permite que os moldes sejam encontrados facilmente em seu código usando grep ou ferramentas similares.
  2. Torna explícito o tipo de casting que você está fazendo e envolve a ajuda do compilador para aplicá-lo. Se você quiser apenas ignorar a constância, poderá usar const_cast, o que não permitirá que você faça outros tipos de conversões.
  3. Os moldes são inerentemente feios – você, como programador, está ignorando como o compilador normalmente trataria seu código. Você está dizendo ao compilador: “Eu sei melhor que você”. Sendo esse o caso, faz sentido que a realização de um casting seja algo moderadamente doloroso, e que eles devam se destacar em seu código, já que eles são uma provável fonte de problemas.

Veja Introdução Eficaz C ++

É sobre quanto tipo de segurança você quer impor.

Quando você escreve (bar) foo (que é equivalente a reinterpret_cast foo se você não tiver fornecido um operador de conversão de tipo), você está dizendo ao compilador para ignorar a segurança de tipo, e apenas faça como é dito.

Quando você escreve static_cast foo você está pedindo ao compilador para checar se a conversão de tipo faz sentido e, para tipos integrais, inserir algum código de conversão.


EDIT 2014-02-26

Eu escrevi essa resposta há mais de 5 anos e entendi errado. (Veja os comentários.) Mas ainda assim fica muito bom!

Os lançamentos de estilo C são fáceis de perder em um bloco de código. Os moldes de estilo C ++ não são apenas melhores práticas; eles oferecem um grau muito maior de flexibilidade.

O reinterpret_cast permite integrar conversões do tipo ponteiro, mas pode ser inseguro se usado incorretamente.

O static_cast oferece uma boa conversão para tipos numéricos, por exemplo, de enums para ints ou ints para floats ou para quaisquer tipos de dados que você tenha certeza do tipo. Não executa nenhuma verificação de tempo de execução.

O dynamic_cast, por outro lado, executará essas verificações sinalizando quaisquer atribuições ou conversões ambíguas. Ele só funciona em pointers e referências e incorre em uma sobrecarga.

Há um par de outros, mas estes são os principais que você vai encontrar.

static_cast, além de manipular pointers para classs, também pode ser usado para realizar conversões explicitamente definidas em classs, bem como para realizar conversões padrão entre os tipos fundamentais:

 double d = 3.14159265; int i = static_cast(d);