Quand doit-on utiliser la fonte statique, la fonte dynamique, la fonte en const et la fonte réinterprétée?

quelles sont les utilisations appropriées de:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • style C cast (type)value
  • Fonction de style coulé type(value)

comment décider lequel utiliser dans quels cas précis?

2098
demandé sur user3728501 2008-12-01 23:11:07

7 réponses

static_cast est le premier moulage que vous devriez essayer d'utiliser. Il fait des choses comme les conversions implicites entre les types (comme int en float , ou pointeur vers void* ), et il peut aussi appeler des fonctions de conversion explicites (ou implicites). Dans de nombreux cas, l'indication explicite static_cast n'est pas nécessaire, mais il est important de noter que la syntaxe T(something) est équivalente à (T)something et devrait être évitée (plus sur ce point plus loin). Un T(something, something_else) est sûr, cependant, et garanti d'appeler le constructeur.

static_cast peut également jeter à travers les hiérarchies de l'héritage. Il n'est pas nécessaire lors de la coulée vers le haut (vers une classe de base), mais lors de la coulée vers le bas il peut être utilisé aussi longtemps qu'il ne passe pas par virtual héritage. Il ne fait pas de vérification, cependant, et il est un comportement non défini à static_cast vers le bas d'une hiérarchie à un type qui n'est pas réellement le type de l'objet.


const_cast peut être utilisé pour supprimer ou ajouter const à une variable; aucun autre cast C++ n'est capable de le supprimer (pas même reinterpret_cast ). Il est important de noter que la modification d'une valeur anciennement const n'est indéterminée que si la variable originale est const ; si vous l'utilisez pour enlever la référence const à quelque chose qui n'a pas été déclaré avec const , c'est sans danger. Cela peut être utile lorsque surcharger des fonctions de membre basées sur const , par exemple. Il peut également être utilisé pour ajouter const à un objet, comme pour appeler une surcharge de fonction d'un membre.

const_cast fonctionne aussi de la même façon sur volatile , bien que ce soit moins commun.


dynamic_cast est utilisé presque exclusivement pour traiter le polymorphisme. Vous pouvez lancer un pointeur ou une référence à n'importe quel type polymorphique pour tout autre type de classe (un type polymorphique a au moins une fonction virtuelle, déclarée ou héritée). Vous pouvez l'utiliser pour plus que simplement le moulage vers le bas -- vous pouvez mouler latéralement ou même vers le haut d'une autre chaîne. Le dynamic_cast cherchera l'objet désiré et le retournera si possible. S'il ne peut pas, il retournera nullptr dans le cas d'un pointeur, ou lancera std::bad_cast dans le cas d'une référence.

dynamic_cast a quelques limites, cependant. Il ne fonctionne pas si il y a plusieurs objets du même type dans la hiérarchie de l'héritage (le soi-disant "diamant redouté") et vous n'utilisez pas l'héritage virtual . Il ne peut également passer que par l'héritage public - il ne pourra jamais passer par l'héritage protected ou private . C'est rarement un problème, cependant, que de telles formes d'héritage sont rares.


reinterpret_cast est la fonte la plus dangereuse, et doit être utilisé avec beaucoup de parcimonie. Il transforme un type directement en un autre-comme le moulage de la valeur d'un pointeur à un autre, ou le stockage d'un pointeur dans un int , ou toutes sortes d'autres choses désagréables. En grande partie, la seule garantie que vous obtenez avec reinterpret_cast est que normalement si vous moulez le résultat vers le type original, vous obtiendrez la même valeur exacte (mais pas si le type intermédiaire est plus petit que le type original). Il y a un certain nombre de conversions que reinterpret_cast ne peut pas faire, aussi. Il est principalement utilisé pour des conversions et des manipulations de bits particulièrement bizarres, comme transformer un flux de données brutes en données réelles, ou stocker des données dans les bits bas d'un pointeur aligné.


les moulages de style C et sont des moulages utilisant (type)object ou type(object) , respectivement. Un casting de style C est défini comme le premier des suivants qui succède:

  • const_cast
  • static_cast (tout en ignorant les restrictions d'accès)
  • static_cast (voir ci-dessus), puis const_cast
  • reinterpret_cast
  • reinterpret_cast , puis const_cast

il peut donc être utilisé en remplacement d'autres moulages dans certains cas, mais peut être extrêmement dangereux en raison de la capacité de passer dans un reinterpret_cast , et ce dernier devrait être préféré quand le moulage explicite est nécessaire, à moins que vous êtes sûr que static_cast réussira ou reinterpret_cast échouera. Même alors, considérez l'option plus longue, plus explicite.

Les moulages de type C

ignorent également le contrôle d'accès lorsqu'ils exécutent un static_cast , ce qui signifie qu'ils ont la capacité d'effectuer une opération qu'aucun autre moulage ne peut effectuer. C'est surtout l' kludge, cependant, et dans mon esprit est juste une autre raison d'éviter les casts de C-style.

2255
répondu coppro 2016-11-16 08:25:06

Utiliser dynamic_cast pour la conversion des pointeurs/références au sein d'une hiérarchie d'héritage.

utiliser static_cast pour les conversions de type ordinaire.

utiliser reinterpret_cast pour réinterpréter de bas niveau des modèles de bits. Utiliser avec une extrême prudence.

utiliser const_cast pour rejeter const/volatile . Évitez cela à moins que vous ne soyez bloqué en utilisant une API const-incorrect.

293
répondu Fred Larson 2014-04-04 07:48:17

(beaucoup d'explications théoriques et conceptuelles ont été données ci-dessus)

ci-Dessous sont quelques-uns des exemples concrets lorsque j'ai utilisé static_cast , dynamic_cast , const_cast , reinterpret_cast .

(renvoie aussi à cela pour comprendre l'explication: http://www.cplusplus.com/doc/tutorial/typecasting / )

static_cast:

OnEventData(void* pData)

{
  ......

  //  pData is a void* pData, 

  //  EventData is a structure e.g. 
  //  typedef struct _EventData {
  //  std::string id;
  //  std:: string remote_id;
  //  } EventData;

  // On Some Situation a void pointer *pData
  // has been static_casted as 
  // EventData* pointer 

  EventData *evtdata = static_cast<EventData*>(pData);
  .....
}

dynamic_cast:

void DebugLog::OnMessage(Message *msg)
{
    static DebugMsgData *debug;
    static XYZMsgData *xyz;

    if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
        // debug message
    }
    else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
        // xyz message
    }
    else/* if( ... )*/{
        // ...
    }
}

const_cast:

// *Passwd declared as a const

const unsigned char *Passwd


// on some situation it require to remove its constness

const_cast<unsigned char*>(Passwd)

reinterpret_cast:

typedef unsigned short uint16;

// Read Bytes returns that 2 bytes got read. 

bool ByteBuffer::ReadUInt16(uint16& val) {
  return ReadBytes(reinterpret_cast<char*>(&val), 2);
}
160
répondu Sumit Arora 2015-07-11 00:22:00

cela pourrait aider si vous connaissez un peu des internes...

static_cast

  • le compilateur C++ sait déjà convertir des types de scalers tels que float en int. Utilisez static_cast pour eux.
  • en cas général de conversion de type A en B , static_cast appelle B 's constructeur passant A comme param. Si B n'a pas un tel constructeur génère alors une erreur de compilation.
  • Cast de A* à B* réussit toujours si A et B sont dans la hiérarchie d'héritage (ou nulle), sinon vous obtenez des erreurs lors de la compilation.
  • Gotcha : si vous lancez pointeur de base vers pointeur dérivé, mais si l'objet réel n'est pas vraiment type dérivé, alors vous don't get error. Vous obtenez mauvais pointeur et segfault à l'exécution. En va de même pour A& à B& .
  • Gotcha : moulé à partir de dérivé à la Base ou viceversa crée nouveau copie! Pour les personnes venant de C#/Java, cela peut être une énorme surprise.

dynamic_cast

  • dynamic_cast utilise des informations de type runtime pour déterminer si cast est valide. Par exemple, (Base*) à (Derived*) peut échouer si le pointeur n'est pas réellement de type dérivé.
  • cela signifie que dynamic_cast est très cher comparé à static_cast!
  • Pour A* à B* , si la fonte n'est pas valide alors dynamic_cast sera de retour nullptr.
  • pour A& à B& si cast est invalide, dynamic_cast lancera l'exception bad_cast.
  • Contrairement aux autres moulages, il y a des temps d'exécution au-dessus.

const_cast

  • alors que static_cast peut faire non-const pour const, il ne peut pas aller dans un autre sens. Le const_cast peut faire les deux.
  • un exemple où cela s'avère pratique est l'itération dans un conteneur comme set<T> qui ne renvoie ses éléments que comme const pour s'assurer que vous ne changez pas sa clé. Cependant si votre intention est de modifier l'objet du non-membres clés alors qu'il devrait être ok. Vous pouvez utiliser const_cast pour supprimer Constance.
  • un autre exemple est quand vous voulez implémenter T& foo() ainsi que const T& foo() . Pour éviter la duplication de code, vous pouvez appliquer const_cast pour retourner la valeur d'une fonction à une autre.

reinterpret_cast

  • cela dit fondamentalement que prendre ces octets à cet endroit de la mémoire et penser à lui comme objet donné.
  • par exemple, vous pouvez charger 4 octets de float à 4 octets d'int pour voir comment les bits dans float ressemble.
  • évidemment, si les données ne sont pas correctes pour le type, vous pouvez obtenir segfault.
  • il n'y a pas de runtime overhead pour cette distribution.
57
répondu ShitalShah 2018-09-27 04:56:49

est-ce que ce répond à votre question?

Je n'ai jamais utilisé reinterpret_cast , et je me demande si le fait de tomber sur une affaire qui en a besoin n'est pas une odeur de mauvais design. Dans la base de code, je travaille sur dynamic_cast est beaucoup utilisé. La différence avec static_cast est qu'un dynamic_cast fait le contrôle d'exécution qui peut être (plus sûr) ou peut ne pas être (plus au-dessus) ce que vous voulez (voir msdn ).

12
répondu andreas buykx 2012-04-04 16:31:31

en plus des autres réponses jusqu'à présent, voici un exemple peu évident où static_cast n'est pas suffisant pour que reinterpret_cast soit nécessaire. Supposons qu'il y ait une fonction qui, dans un paramètre de sortie, renvoie des pointeurs vers des objets de différentes classes (qui ne partagent pas de classe de base commune). Un exemple réel d'une telle fonction est CoCreateInstance() (voir le dernier paramètre, qui est en fait void** ). Supposons que vous demandiez à cette classe particulière d'objet fonction, de sorte que vous connaissez à l'avance le type pour le pointeur (ce que vous faites souvent pour les objets COM). Dans ce cas, vous ne pouvez pas lancer pointeur sur votre pointeur dans void** avec static_cast : vous avez besoin de reinterpret_cast<void**>(&yourPointer) .

dans le code:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    //static_cast<void**>(&pNetFwPolicy2) would give a compile error
    reinterpret_cast<void**>(&pNetFwPolicy2) );

cependant, static_cast fonctionne pour les pointeurs simples (pas de pointeurs vers les pointeurs), de sorte que le code ci-dessus peut être réécrit pour éviter reinterpret_cast (à un prix d'une variable supplémentaire) de la manière suivante:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    &tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);
12
répondu Serge Rogatch 2016-02-22 10:30:03

alors que d'autres réponses décrivaient bien toutes les différences entre les casts C++, j'aimerais ajouter une petite note expliquant pourquoi vous ne devriez pas utiliser les casts C-style (Type) var et Type(var) .

Pour le C++ débutants C-style jette ressemble en apparence le sur-ensemble de l'opération sur C++ jette (static_cast<>(), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) et si quelqu'un pourrait préférez sur le C++ jette. En fait, c-style cast est le superset et plus court à écrire.

le problème principal des plâtres de style C est qu'ils cachent l'intention réelle du développeur de la distribution. Les coulées de style C peuvent faire pratiquement tous les types de coulées à partir de coulées normalement sûres faites par static_cast<>() et dynamic_cast<>() à des coulées potentiellement dangereuses comme const_cast<>(), où le modificateur de const peut être enlevé de sorte que les variables de const peuvent être modifiées et réinterpret_cast<>() qui peut même réinterpréter des valeurs entières à des pointeurs.

Voici l'échantillon.

int a=rand(); // Random number.

int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.

int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.

int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.

*pa4=5; // Program crashes.

la principale raison pour laquelle les casts C++ ont été ajoutés au langage était de permettre à un développeur de clarifier ses intentions - pourquoi il va faire ce cast. En utilisant C-style casts qui sont parfaitement valides en C++ vous rendez votre code moins lisible et plus sujet aux erreurs surtout pour les autres développeurs qui n'ont pas créé votre code. Ainsi, pour rendre votre code plus lisible et explicite, vous devriez toujours préférer les casts C++ aux casts C-style.

voici une courte citation de Bjarne Stroustrup (l'auteur de C++) livre le langage de programmation C++ 4ème édition-page 302.

ce moulage de style C est beaucoup plus dangereux que les opérateurs de conversion nommés parce que la notation est plus difficile à repérer, dans un large programme et le type de conversion prévu par le programmeur n'est pas explicite.

4
répondu Timmy_A 2018-08-22 11:18:21