Pergunta

Ouvi dizer que a função static_cast deve ser preferido para C-estilo ou fundição de estilo simples função. Isso é verdade? Por quê?

Foi útil?

Solução

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

A static_cast<>() é geralmente segura. Há uma conversão válida na língua, ou um construtor apropriado que torna possível. A única vez que é um pouco arriscado é quando você joga para baixo para uma classe herdada; você deve certificar-se de que o objeto é realmente o descendente que afirmam que é, por meios externos à linguagem (como uma bandeira no objeto). Um dynamic_cast<>() é segura, desde que o resultado é verificado (ponteiro) ou uma possível excepção, é tomado em consideração (referência).

A reinterpret_cast<>() (ou um const_cast<>()), por outro lado é sempre perigoso. Você dizer ao compilador: "confie em mim: eu sei que isso não se parece com um foo (Isso parece como se não é mutável), mas é".

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

Vamos supor estes:

class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

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

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

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

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!!!

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

O segundo problema é que os moldes de estilo C são muito difíceis de localizar. Em expressões complexas, pode ser muito difícil ver moldes de estilo C. É praticamente impossível escrever uma ferramenta automatizada que precisa para localizar moldes de estilo C (por exemplo uma ferramenta de busca) sem um soprado C ++ compilador front-end completa. Por outro lado, é fácil de pesquisa para "static_cast <" ou "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.

Isso significa que, não só são moldes de estilo C mais perigoso, mas é muito mais difícil encontrá-los todos para se certificar de que eles estão corretos.

Outras dicas

Uma dica pragmática:. Você pode facilmente pesquisar a palavra-chave static_cast em seu código-fonte, se você pretende arrumar o projeto

Em suma :

  1. static_cast<>() dá-lhe uma capacidade de verificação de tempo de compilação, C-Style elenco não.
  2. static_cast<>() pode ser notado facilmente em qualquer lugar dentro de um código de fonte C ++; em contraste, C_Style elenco é mais difícil de detectar.
  3. As intenções são transmitidas muito melhor usando moldes C ++.

Mais Explicação :

Os executa elenco estáticos conversões entre tipos compatíveis . isto é semelhante ao molde de estilo C, mas é mais restritiva. Por exemplo, o fundido de estilo C permitirá um ponteiro de inteiro ao ponto de um carvão animal.

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

Uma vez que isso resulta em um ponteiro que aponta 4 bytes para 1 byte de alocado memória, escrevendo para este ponteiro vai ou causar um erro de tempo de execução ou irá substituir alguma memória adjacente.

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

Em contraste com o elenco de estilo C, o elenco estática permitirá que o compilador para verificar se os tipos ponteiro e pointee de dados são compatível, o que permite que o programador para travar este incorrecta atribuição ponteiro durante a compilação.

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

Leia mais em:
Qual é a diferença entre static_cast <> e fundição estilo C
e
elenco regular vs static_cast vs. dynamic_cast

A questão é maior do que apenas usando static_cast murchar ou fundição estilo C, porque há coisas diferentes que acontecem quando usando moldes de estilo C. O C ++ lançando operadores têm a intenção de fazer essas operações mais explícito.

No static_cast superfície e moldes estilo C parecem a mesma coisa, por exemplo, quando lançando um valor para outro:

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

Ambos elenco o valor inteiro para um duplo. No entanto quando se trabalha com ponteiros 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<char*>( new int( 5 ) ); //(3) compile time error

Neste exemplo (1) talvez OK porque o objeto apontado por A é realmente uma instância de B. Mas e se você não sabe em que ponto do código o que é um fato aponta para? (2) talvez perfeitamente legal (você só quer olhar para um byte do inteiro), mas também pode ser um erro, caso em que um erro seria bom, como (3). O C ++ lançando operadores têm a intenção de expor essas questões no código, fornecendo em tempo de compilação ou tempo de execução erros quando possível.

Assim, por rigorosa "fundição valor" você pode usar static_cast. Se você quer em tempo de execução fundição polimórfico de ponteiros usar dynamic_cast. Se você realmente quer esquecer tipos, você pode usar reintrepret_cast. E para const a poucos passos para fora da janela existe const_cast.

Eles apenas fazem o código de modo mais explícito que parece que você sabe o que você estava fazendo.

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

  1. Permite moldes de ser encontrado facilmente em seu código usando grep ou similar Ferramentas.
  2. explicita que tipo do elenco que está fazendo, e se engajar a ajuda do compilador em aplicá-la. Se você só quer jogar fora const-ness, então você pode usar const_cast, que não permitirá que você para fazer outros tipos de conversões.
  3. moldes são inerentemente feio - você como um programador estão anulando a forma como o compilador normalmente seria tratar o seu código. Você está dizendo ao compilador, "Eu sei melhor do que você." Sendo esse o caso, faz sentido que a realização de um molde deve ser um moderadamente coisa dolorosa para fazer, e que eles deveriam ficar fora em sua código, uma vez que são uma fonte provável de problemas.

Effective C ++ Introdução

É sobre o quanto tipo de segurança que pretende impor.

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

Quando você escreve static_cast<bar> foo você está pedindo o compilador para, pelo menos verificar que a conversão de tipo faz sentido e, para tipos integrais, para inserir algum código de conversão.


EDIT 2014/02/26

Eu escrevi esta resposta mais de 5 anos atrás, e eu entendi errado. (Veja comentários.) Mas ele ainda fica upvotes!

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

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

moldes C Estilo são fáceis de perder em um bloco de código. elencos estilo C ++ não são apenas melhor prática; eles oferecem um grau maior tanto de flexibilidade.

reinterpret_cast permite integrante de conversões de tipo ponteiro, porém, pode ser perigoso se for mal utilizado.

ofertas static_cast boa conversão para tipos numéricos por exemplo de como enums para ints ou ints para flutuadores ou quaisquer tipos de dados que você está confiante de tipo. Ele não executa qualquer verificação de tempo de execução.

dynamic_cast por outro lado vai executar essas verificações sinalização quaisquer atribuições ambíguas ou conversões. Ele só funciona em ponteiros e referências e incorre uma sobrecarga.

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top