Coulée régulière vs. coulée statique vs. coulée dynamique [dupliquer]

cette question a déjà une réponse ici:

j'écris du code C et c++ depuis presque vingt ans, mais il y a un aspect de ces langues que je n'ai jamais vraiment compréhensible. J'ai évidemment utilisé des moulages réguliers i.e.

MyClass *m = (MyClass *)ptr;

partout, mais il semble y avoir deux autres types de moulages, et je ne sais pas la différence. Quelle est la différence entre les lignes de code suivantes?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);
1501
demandé sur R. Martinho Fernandes 2008-08-26 17:20:55
la source

8 ответов

static_cast

static_cast est utilisé pour les cas où vous voulez essentiellement inverser une conversion implicite, avec quelques restrictions et additions. static_cast n'effectue aucun contrôle d'exécution. Cela devrait être utilisé si vous savez que vous faites référence à un objet d'un type spécifique, et donc un chèque serait inutile. Exemple:

void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

dans cet exemple, vous savez que vous avez passé un objet MyClass , et donc il n'y a pas besoin pour un contrôle d'exécution pour s'assurer cela.

dynamic_cast

dynamic_cast est utile lorsque vous ne savez pas ce que le type dynamique de l'objet. Il renvoie un pointeur nul si l'objet auquel il est fait référence ne contient pas le type de base (lorsque vous lancez une référence, une exception bad_cast est lancée dans ce cas).

if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

vous ne pouvez pas utiliser dynamic_cast type d'argument n'est pas polymorphe. Par exemple, le code suivant n'est pas valide, car Base ne contient aucune fonction virtuelle:

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

un" up-cast "(moulé à la classe de base) est toujours valable avec les deux static_cast et dynamic_cast , et aussi sans aucun cast, comme un" up-cast " est une conversion implicite.

Distribution Régulière

ces moulages sont également appelés moulages de style C. Un casting de style C est essentiellement identique à essayer une série de séquences de casts C++, et de prendre le premier cast C++ qui fonctionne, sans jamais considérer dynamic_cast . Inutile de dire que c'est beaucoup plus puissant car il combine tous les const_cast , static_cast et reinterpret_cast , mais il est également dangereux , parce qu'il n'utilise pas dynamic_cast .

en outre, les moulages de style C non seulement vous permettent de le faire, mais ils vous permettent également de mouler en toute sécurité dans une classe de base privée, tandis que l '" équivalent" static_cast séquence serait vous donner une erreur de compilation.

certaines personnes préfèrent les moulages de style C à cause de leur brièveté. Je les utilise uniquement pour les moulages numériques, et j'utilise les moulages c++ appropriés lorsque des types définis par l'utilisateur sont impliqués, car ils fournissent un contrôle plus strict.

1432
répondu Johannes Schaub - litb 2017-07-09 06:23:43
la source

coulée statique

la coulée statique effectue des conversions entre types compatibles. Il est similaire à la distribution de style C, mais est plus restrictif. Par exemple, le cast de style C permettrait à un pointeur entier de pointer vers un char.

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

Puisqu'il en résulte un pointeur de 4 octets pointant vers 1 octet de mémoire allouée, l'écriture sur ce pointeur causera soit une erreur de temps d'exécution ou écrasera une mémoire adjacente.

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

contrairement à la distribution en C-style, la distribution statique permettra au compilateur de vérifier que les types de données pointeur et pointé sont compatibles, ce qui permet au programmeur de saisir cette affectation incorrecte de pointeur pendant la compilation.

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

réinterprétation cast

pour forcer la conversion de pointeur, de la même manière que la fonte de style C fait en arrière-plan, la fonte de réinterprétation serait utilisée à la place.

int *r = reinterpret_cast<int*>(&c); // forced conversion

cette fonte traite les conversions entre certains types indépendants, tels que d'un type de pointeur à un autre type de pointeur incompatible. Il va simplement effectuer une copie binaire des données sans modifier le motif bit sous-jacent. Il est à noter que le résultat d'une telle opération de faible niveau est spécifique au système et donc non portable. Il doit être utilisé avec prudence si elle ne peut pas être évitée complètement.

Dynamic cast

This l'un n'est utilisé que pour convertir les pointeurs d'objet et les références d'objet en d'autres types de pointeur ou de référence dans la hiérarchie d'héritage. C'est le seul cast qui s'assure que l'objet pointé vers peut être converti, en effectuant un contrôle d'exécution que le pointeur se réfère à un objet complet du type de destination. Pour que cette vérification soit possible, l'objet doit être polymorphe. C'est-à-dire que la classe doit définir ou hériter au moins une fonction virtuelle. C'est parce que le compilateur ne générez les informations de type run-time nécessaires pour de tels objets.

exemples de coulée dynamique

dans l'exemple ci-dessous, un pointeur MyChild est converti en pointeur MyBase à l'aide d'un moulage dynamique. Cette conversion dérivé-à-base réussit, parce que l'objet enfant inclut un objet de base complet.

class MyBase 
{ 
  public:
  virtual void test() {}
};
class MyChild : public MyBase {};



int main()
{
  MyChild *child = new MyChild();
  MyBase  *base = dynamic_cast<MyBase*>(child); // ok
}

l'exemple suivant tente de convertir un pointeur MyBase en pointeur MyChild. Depuis le L'objet de Base ne contient pas un objet enfant complet cette conversion pointeur échouera. Pour l'indiquer, la fonte dynamique renvoie un pointeur nul. Cela donne un moyen commode pour vérifier si oui ou non une conversion a réussi pendant l'exécution.

MyBase  *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);


if (child == 0) 
std::cout << "Null pointer returned";

si une référence est convertie à la place d'un pointeur, la distribution dynamique échouera alors en lançant une exception bad_cast. Cela doit être traité en utilisant une déclaration d'essai.

#include <exception>
// …  
try
{ 
  MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e) 
{ 
  std::cout << e.what(); // bad dynamic_cast
}

coulée dynamique ou statique

l'avantage d'utiliser un plâtre dynamique est qu'il permet au programmeur de vérifier si une conversion a réussi ou non pendant l'exécution. L'inconvénient est qu'il y a un dépassement de performance associé à cette vérification. Pour cette raison, l'utilisation d'une coulée statique aurait été préférable dans le premier exemple, parce qu'une conversion dérivée en base n'échouera jamais.

MyBase *base = static_cast<MyBase*>(child); // ok

Toutefois, dans le deuxième exemple la conversion peut réussir ou échouer. Il échouera si L'objet MyBase contient une instance MyBase et il réussira s'il contient une instance MyChild. Dans certaines situations, cela peut ne pas être connu avant l'exécution. Dans ce cas, la coulée dynamique est un meilleur choix que la coulée statique.

// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);

si la conversion de base à dérivée avait été effectuée en utilisant une coulée statique au lieu d'une coulée dynamique, la conversion n'aurait pas échoué. Il aurait renvoie un pointeur qui renvoie à un objet incomplet. Référence à un tel pointeur peut conduire à des erreurs d'exécution.

// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);

// Incomplete MyChild object dereferenced
(*child);

Const "jeté 1519150920"

celui-ci est principalement utilisé pour ajouter ou supprimer le modificateur const d'une variable.

const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const

bien que const cast permette de changer la valeur d'une constante, le faire est toujours un code invalide qui peut causer une erreur d'exécution. Cela pourrait se produire par exemple si la constante était situé dans une section de mémoire en lecture seule.

*nonConst = 10; // potential run-time error

Const cast est utilisé principalement quand il y a une fonction qui prend un argument pointeur non-constant, même si elle ne modifie pas le pointeur.

void print(int *p) 
{
   std::cout << *p;
}

la fonction peut alors passer une variable constante en utilisant un jet de const.

print(&myConst); // error: cannot convert 
                 // const int* to int*

print(nonConst); // allowed

Source et plus D'explications

123
répondu Breeze 2013-08-24 05:55:13
la source

Vous devriez regarder l'article Programmation en C++/Type de Casting .

il contient une bonne description de tous les différents types de moulage. Extrait du lien ci-dessus:

const_cast

const_cast (expression)<> () est utilisé pour ajouter/supprimer const (ness) (ou Volatil-ness) d'une variable.

static_cast

static_cast (expression) le static_cast<>() est utilisé pour lancer entre les types d'entiers. 'par exemple' char->long, int->court etc.

coulée statique est également utilisé pour couler des aiguilles à des types connexes, pour exemple casting void* vers le type approprié.

dynamic_cast

Dynamic cast est utilisé pour convertir des pointeurs et des références à l'exécution, généralement, pour les fins de la conversion d'une pointeur ou une référence vers le haut ou vers le bas une chaîne d'héritage (hiérarchie d'héritage).

dynamic_cast (expression)

le type cible doit être un pointeur ou un type de référence, et le l'expression doit correspondre à un pointeur ou d'une référence. Dynamic cast works uniquement lorsque le type d'objet pour lequel l'expression fait référence est compatible avec le type de cible et la classe de base a au moins un fonction membre virtuelle. Si non, et le type de l'expression de vote est un pointeur, NULL est retourné, si une distribution dynamique sur une référence échoue, une exception bad_cast est lancée. Quand il n'est pas en panne, la dynamique cast renvoie un pointeur ou une référence du type cible à l'objet à laquelle l'expression fait référence.

reinterpret_cast

réinterpréter moulé simplement jette un type bitwise à un autre. Un pointeur ou le type intégral peut être moulé à n'importe quel autre avec réinterprétation moulage, facilement permettant abus. Par exemple, avec réinterpréter cast pourrait, de façon peu sûre, lancer un pointeur entier sur un pointeur de corde.

72
répondu TJ Seabrooks 2014-04-01 22:00:19
la source

éviter d'utiliser des moulages de style C.

C-style casts sont un mélange de const et réinterpréter cast, et il est difficile de trouver-et-remplacer dans votre code. Un programmeur d'application C++ devrait éviter la distribution C-style.

23
répondu ugasoft 2014-01-23 01:09:03
la source

pour info, je crois que Bjarne Stroustrup est cité comme disant qu'il faut éviter les casts de style C et qu'il faut utiliser static_cast ou dynamic_cast si possible.

Barne de Stroustrup style C++ FAQ

prenez ce conseil pour ce que vous voulez. Je suis loin d'être un gourou du C++.

21
répondu Jason Baker 2015-03-03 14:19:38
la source

C-style jette un amalgame entre les const_cast, static_cast, et reinterpret_cast.

je souhaite que le C++ n'a pas de style C jette. Les moulages C++ se démarquent bien (comme ils devraient le faire; les moulages sont normalement une indication de faire quelque chose de mal) et distinguent correctement les différents types de conversion que les moulages effectuent. Ils permettent également d'écrire des fonctions similaires, par exemple boost::lexical_cast, ce qui est assez agréable du point de vue de la cohérence.

10
répondu DrPizza 2008-08-26 17:38:35
la source

dynamic_cast a la vérification de type d'exécution et ne fonctionne qu'avec des références et des pointeurs, tandis que static_cast n'offre pas la vérification de type d'exécution. Pour des informations complètes, voir L'article MSDN opérateur static_cast .

8
répondu Inisheer 2014-01-23 01:05:29
la source

dynamic_cast ne supporte que les pointeurs et les types de référence. Il retourne NULL si le casting est impossible si le type est un pointeur ou lève une exception si le type est un type de référence. Par conséquent, dynamic_cast peut être utilisé pour vérifier si un objet est d'un type donné, static_cast ne peut pas (vous finirez simplement avec une valeur invalide).

C-style (et d'autres) des moulages ont été couverts dans les autres réponses.

7
répondu larsmoa 2016-12-13 10:41:02
la source

Autres questions sur c++ pointers casting