J'ai entendu dire que, en C ++, la fonction static_cast devrait être préférée au style C ou au simple coulage de style de fonction. Est-ce vrai? Pourquoi?
Réponses
Trop de publicités?La raison principale est que le classique C de moulages de ne pas faire de distinction entre ce que nous appelons static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
, et dynamic_cast<>()
. Ces quatre choses sont complètement différentes.
Un static_cast<>()
est généralement sans danger. Il est valable de conversion dans la langue, ou un constructeur approprié qui la rend possible. Le seul moment où c'est un peu risqué, c'est quand vous avez jeté à une classe héritée; vous devez vous assurer que l'objet est en fait le descendant que vous prétendez qu'il est, par des moyens externes à la langue (comme un drapeau dans l'objet). Un dynamic_cast<>()
est sûre, tant que le résultat est vérifié (pointeur) ou une exception possible est pris en compte (de référence).
Un reinterpret_cast<>()
(ou const_cast<>()
) sur l'autre main est toujours dangereux. Vous dire au compilateur: "faites-moi confiance: je sais que cela ne ressemble pas à un foo
(c'est comme si il n'est pas mutable), mais il est".
Le premier problème est qu'il est presque impossible de dire où l'on va se produire dans un style C cast sans regarder grand et disperser les morceaux de code et de connaître toutes les règles.
Supposons ces:
class CMyClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
Maintenant, ces deux sont compilés de la même façon:
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
Cependant, nous allons voir ce presque identiques code:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reiterpret_cast<>
// and it's wrong!!!
Comme vous pouvez le voir, il n'est pas facile de distinguer entre les deux situations, sans le savoir beaucoup au sujet de toutes les classes concernées.
Le deuxième problème est que le style C moulages sont trop difficiles à localiser. Dans des expressions complexes, il peut être très difficile de voir C-style jette. Il est pratiquement impossible d'écrire un outil automatisé qui doit rechercher du C-style jette (par exemple un outil de recherche) sans une véritable compilateur C++ avant la fin de l'. D'autre part, il est facile de rechercher pour "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.
Cela signifie que, non seulement C-style jette plus dangereux, mais il est beaucoup plus difficile de les trouver tous à s'assurer qu'ils sont corrects.
La question est plus grand que juste l'aide de dépérir static_cast ou C style coulée parce qu'il y a différentes choses qui se produisent lors de l'utilisation de C style jette. Le C++ casting opérateurs sont destinés à rendre ces opérations plus explicite.
Sur la surface static_cast et C style jette apparaissent à la même chose, par exemple lors de la conversion d'une valeur à une autre:
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
Ces deux cast la valeur entière d'un double. Cependant lorsque l'on travaille avec des pointeurs, les choses deviennent plus compliquées. quelques exemples:
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
Dans cet exemple (1) peut-être OK parce que l'objet pointé par Un est vraiment une instance de B. Mais que faire si vous ne savez pas à ce point dans le code ce une réalité? (2) peut-être parfaitement légal(vous ne voulez regarder un octet de l'entier), mais il pourrait aussi être une erreur, dans ce cas, une erreur serait sympa, comme (3). Le C++ casting opérateurs sont destinées à exposer ces questions dans le code en fournissant au moment de la compilation ou de l'exécution des erreurs lorsque cela est possible.
Donc, pour la stricte valeur "casting", vous pouvez utiliser static_cast. Si vous souhaitez exécuter en temps polymorphe de la coulée de pointeurs utilisation dynamic_cast. Si vous voulez vraiment oublier types, vous pouvez utiliser reintrepret_cast. Et il suffit de jeter const hors de la fenêtre il y a const_cast.
Ils suffit de rendre le code plus explicite, de sorte qu'il ressemble vous savez ce que vous faisiez.
C'est au sujet de combien de type de sécurité que vous voulez imposer.
Lorsque vous écrivez (bar) foo
(ce qui est équivalent à reinterpret_cast<bar> foo
si vous n'avez pas fourni un opérateur de conversion) en vous disant que le compilateur ignore le type de sécurité, et il suffit de faire comme il est dit.
Lorsque vous écrivez static_cast<bar> foo
vous de demander au compilateur de vérifier au moins que la conversion de type a de sens et, pour les types intégraux, pour insérer du code de conversion.
EDIT 2014-02-26
J'ai écrit cette réponse depuis plus de 5 ans, et je l'ai eu tort. (Voir les commentaires.) Mais il obtient toujours upvotes!