Moulage statique
Le static cast effectue des conversions entre types compatibles. Il est similaire au cast de style C, mais est plus restrictif. Par exemple, le cast de style C permettrait à un pointeur d'entier de pointer vers un char.
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, écrire sur ce pointeur provoquera une erreur d'exécution ou écrasera de la mémoire adjacente.
*p = 5; // run-time error: stack corruption
Contrairement au cast de style C, le cast statique permet au compilateur de vérifier que les types de données du pointeur et du pointeur sont compatibles, ce qui permet au programmeur de détecter cette affectation incorrecte du pointeur pendant la compilation.
int *q = static_cast<int*>(&c); // compile-time error
Réinterpréter le casting
Pour forcer la conversion du pointeur, de la même manière que le cast de style C le fait en arrière-plan, le cast reinterpret serait utilisé à la place.
int *r = reinterpret_cast<int*>(&c); // forced conversion
Ce cast gère les conversions entre certains types non liés, par exemple d'un type de pointeur vers un autre type de pointeur incompatible. Elle effectue simplement une copie binaire des données sans modifier le modèle binaire sous-jacent. Notez que le résultat d'une telle opération de bas niveau est spécifique au système et n'est donc pas portable. Elle doit être utilisée avec prudence si elle ne peut être évitée.
Distribution dynamique
Celui-ci est uniquement utilisé pour convertir les pointeurs d'objets et les références d'objets en d'autres types de pointeurs ou de références dans la hiérarchie d'héritage. C'est le seul cast qui garantit que l'objet pointé peut être converti, en effectuant une vérification à l'exécution que le pointeur fait référence à un objet complet du type de destination. Pour que cette vérification à l'exécution soit possible, l'objet doit être polymorphe. C'est-à-dire que la classe doit définir ou hériter d'au moins une fonction virtuelle. En effet, le compilateur ne génère les informations de type nécessaires à l'exécution que pour de tels objets.
Exemples de distribution dynamique
Dans l'exemple ci-dessous, un MyChild
est converti en un pointeur MyBase
en utilisant une conversion dynamique. Cette conversion dérivée-base réussit, car l'objet Child comprend un objet 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 MyBase
pointeur vers un MyChild
pointeur. Comme l'objet Base ne contient pas d'objet Child complet, cette conversion de pointeur échouera. Pour l'indiquer, le cast dynamique renvoie un pointeur nul. Cela donne un moyen pratique de vérifier si une conversion a réussi ou non 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 au lieu d'un pointeur, le cast dynamique échouera alors en lançant un bad_cast
exception. Celle-ci doit être traitée à l'aide d'une try-catch
déclaration.
#include <exception>
// …
try
{
MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e)
{
std::cout << e.what(); // bad dynamic_cast
}
Distribution dynamique ou statique
L'avantage d'utiliser un cast 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 une surcharge de performance associée à cette vérification. Pour cette raison, l'utilisation d'un cast statique aurait été préférable dans le premier exemple, car une conversion dérivé-base n'échouera jamais.
MyBase *base = static_cast<MyBase*>(child); // ok
Cependant, dans le deuxième exemple, la conversion peut soit réussir, soit échouer. Elle échouera si le MyBase
contient un MyBase
et elle réussira si elle contient une MyChild
exemple. Dans certaines situations, cela peut ne pas être connu avant l'exécution. Lorsque c'est le cas, le cast dynamique est un meilleur choix que le cast statique.
// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);
Si la conversion base/dérivée avait été effectuée en utilisant un cast statique au lieu d'un cast dynamique, la conversion n'aurait pas échoué. Elle aurait renvoyé un pointeur faisant référence à un objet incomplet. Le déréférencement d'un tel pointeur peut entraîner des erreurs d'exécution.
// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
// Incomplete MyChild object dereferenced
(*child);
Const cast
Celui-ci est principalement utilisé pour ajouter ou supprimer l'élément const
modificateur d'une variable.
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const
Bien que const
cast permet de modifier la valeur d'une constante, cela reste du code invalide qui peut provoquer une erreur d'exécution. Cela peut se produire, par exemple, si la constante est située dans une section de la mémoire en lecture seule.
*nonConst = 10; // potential run-time error
const
En revanche, le cast est utilisé principalement lorsqu'il existe 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;
}
On peut ensuite passer à la fonction une variable constante en utilisant une fonction const
la distribution.
print(&myConst); // error: cannot convert
// const int* to int*
print(nonConst); // allowed
Source et autres explications
72 votes
Je n'appellerais pas l'ancien cast de style C un "cast normal" en C++, car c'est tout sauf cela. Vous ne devriez généralement pas l'utiliser en C++, surtout avec les classes, il est tout simplement trop facile de faire des erreurs avec. Son utilisation est le signe d'un programmeur C qui est passé au C++ mais qui n'a pas encore tout à fait appris le C++.
134 votes
Comment une question avec une réponse peut-elle être une duplication d'une question sans réponse ? de plus, cette question a été posée plus tôt que l'"originale".
7 votes
@Vladp Au cas où vous vous poseriez encore la question, ou que quelqu'un d'autre lise ceci et se demande . (De plus, pour mémoire, ce n'est pas un modérateur qui a fermé cette page, mais un utilisateur avec un mot de passe. marteau-pilon )
5 votes
Pour info, le question liée a beaucoup plus de votes positifs et les réponses ont également beaucoup plus de votes positifs. De plus, la question liée a quelques de bons exemples non théoriques . (En outre, la question liée ne fait pas référence de manière incorrecte à la syntaxe de typecast de style C en tant que "regular cast").