Pourquoi utiliser static_cast (x) au lieu de (int) x?

J’ai entendu dire que la fonction static_cast devrait être préférée à la static_cast style C ou simple. Est-ce vrai? Pourquoi?

La principale raison est que les static_cast<>() C classiques ne font aucune 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 sûr. Il existe une conversion valide dans le langage ou un constructeur approprié qui le rend possible. La seule fois où il est un peu risqué, c’est lorsque vous passez à une classe héritée; vous devez vous assurer que l’object est réellement le descendant que vous prétendez être, par des moyens externes au langage (comme un drapeau dans l’object). Un dynamic_cast<>() est sûr tant que le résultat est vérifié (pointeur) ou qu’une exception possible est prise en compte (référence).

Un reinterpret_cast<>() (ou un const_cast<>() ) en revanche est toujours dangereux. Vous dites au compilateur: “croyez-moi: je sais que cela ne ressemble pas à un foo (cela semble ne pas être mutable), mais c’est”.

Le premier problème est qu’il est presque impossible de dire lequel se produira dans une dissortingbution de style C sans regarder en grand et disperser des morceaux de code et 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 manière:

 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 

Cependant, voyons ce code presque identique:

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

Comme vous pouvez le voir, il n’y a pas de moyen facile de distinguer les deux situations sans en savoir beaucoup sur toutes les classes impliquées.

Le deuxième problème est que les moulages de style C sont trop difficiles à localiser. Dans les expressions complexes, il peut être très difficile de voir des moulages de style C. Il est pratiquement impossible d’écrire un outil automatisé qui nécessite de localiser des moulages de style C (par exemple un outil de recherche) sans une interface frontale complète du compilateur C ++. D’autre part, il est facile de rechercher “static_cast <" ou "reinterpret_cast <".

 pOther = reinterpret_cast(pSomething); // No comstackr 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 les moulages de style C sont plus dangereux, mais il est beaucoup plus difficile de les trouver tous pour s’assurer qu’ils sont corrects.

Un conseil pragmatique: vous pouvez rechercher facilement le mot-clé static_cast dans votre code source si vous prévoyez de mettre le projet en ordre.

En bref :

  1. static_cast<>() vous donne une capacité de vérification du temps de compilation, contrairement à la dissortingbution C-Style.
  2. static_cast<>() peut être facilement repéré n’importe où dans un code source C ++; en revanche, le casting de C_Style est plus difficile à repérer.
  3. Les intentions sont beaucoup mieux véhiculées en utilisant les castes C ++.

Plus d’explication :

La dissortingbution statique effectue des conversions entre les types compatibles . Il est similaire à la dissortingbution de style C, mais est plus ressortingctif. Par exemple, la dissortingbution de style C permettrait à un pointeur entier de pointer vers un caractère.

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

Comme il en résulte un pointeur de 4 octets pointant sur 1 octet de mémoire allouée, l’écriture dans ce pointeur provoquera une erreur d’exécution ou écrasera une mémoire adjacente.

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

Contrairement à la dissortingbution de style C, la dissortingbution statique permettra au compilateur de vérifier que les types de données pointeur et pointeur sont compatibles, ce qui permet au programmeur de détecter cette mauvaise affectation de pointeur lors de la compilation.

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

En savoir plus sur:
Quelle est la différence entre static_cast <> et le casting de style C
et
Dissortingbution régulière vs. static_cast vs. dynamic_cast

La question est plus importante que d’utiliser simplement un élément static_cast ou un style C, car il existe différentes choses lors de l’utilisation de castings de style C. Les opérateurs de casting C ++ sont destinés à rendre ces opérations plus explicites.

Sur la surface, les casts static_cast et C apparaissent de la même manière, par exemple lors de la conversion d’une valeur en une autre:

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

Les deux convertissent la valeur entière en double. Cependant, lorsque vous travaillez avec des pointeurs, les choses se compliquent. 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( new int( 5 ) ); //(3) comstack time error 

Dans cet exemple (1), peut-être OK, car l’object désigné par A est en réalité une instance de B. Mais que se passe-t-il si vous ne savez pas à ce point dans quel code pointe réellement un object? (2) peut-être parfaitement légal (vous voulez seulement regarder un octet de l’entier), mais cela pourrait aussi être une erreur, auquel cas une erreur serait bien, comme (3). Les opérateurs de casting C ++ sont destinés à exposer ces problèmes dans le code en fournissant des erreurs de compilation ou d’exécution lorsque cela est possible.

Donc, pour un “casting de valeur” ssortingct, vous pouvez utiliser static_cast. Si vous souhaitez que le casting polymorphe d’exécution de pointeurs utilise dynamic_cast. Si vous voulez vraiment oublier les types, vous pouvez utiliser reintrepret_cast. Et juste jeter const la fenêtre il y a const_cast.

Ils ne font que rendre le code plus explicite, de sorte qu’il semble que vous sachiez ce que vous faisiez.

static_cast signifie que vous ne pouvez pas accidentellement const_cast ou const_cast , ce qui est une bonne chose.

  1. Permet de trouver facilement des dissortingbutions dans votre code en utilisant grep ou des outils similaires.
  2. Explique le type de dissortingbution que vous faites et engagez l’aide du compilateur pour le faire respecter. Si vous souhaitez uniquement supprimer les constantes, vous pouvez utiliser const_cast, ce qui ne vous permettra pas d’effectuer d’autres types de conversions.
  3. Les moulages sont insortingnsèquement moche – en tant que programmeur, vous annulez la manière dont le compilateur traiterait normalement votre code. Vous dites au compilateur: “Je sais mieux que vous.” Cela étant, il est logique que l’exécution d’une dissortingbution soit une chose modérément douloureuse à faire, et qu’elle doive restr dans votre code, car elles constituent une source probable de problèmes.

Voir Introduction au C ++ efficace

Il s’agit de la sécurité de type que vous souhaitez imposer.

Lorsque vous écrivez (bar) foo (ce qui équivaut à reinterpret_cast foo si vous n’avez pas fourni d’opérateur de conversion de type), vous dites au compilateur d’ignorer la sécurité de type et de faire ce qu’il dit.

Lorsque vous écrivez static_cast foo vous demandez au compilateur de vérifier au moins que la conversion de type est logique et, pour les types intégraux, d’insérer du code de conversion.


EDIT 2014-02-26

J’ai écrit cette réponse il y a plus de 5 ans et je me suis trompé. (Voir les commentaires.) Mais il y a toujours des votes positifs!

Les styles C sont faciles à rater dans un bloc de code. Les fontes de style C ++ ne sont pas seulement de meilleures pratiques; ils offrent une plus grande flexibilité.

reinterpret_cast permet l’intégrale des conversions de type pointeur, mais peut être dangereuse si elle est mal utilisée.

static_cast offre une bonne conversion pour les types numériques, par exemple de enums en ints ou ints en flottants ou tout type de données dont vous êtes sûr du type. Il n’effectue aucune vérification d’exécution.

Par contre, dynamic_cast effectuera ces contrôles en signalant toute affectation ou conversion ambiguë. Il ne fonctionne que sur des pointeurs et des références et entraîne une surcharge.

Il y en a quelques autres mais ce sont les principaux que vous rencontrerez.

static_cast, en plus de manipuler des pointeurs vers des classes, peut également être utilisé pour effectuer des conversions explicitement définies dans des classes, ainsi que pour effectuer des conversions standard entre types fondamentaux:

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