static_cast, dynamic_cast, const_cast, reinterpret_cast : quand utiliser quoi ?

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : pourquoi C++ ne pardonne pas les erreurs de conversion de type ?



Salut, l'ami ! Si tu as déjà programmé en C++, tu as forcément rencontré une situation où le compilateur râle à cause d'une incompatibilité de types. Et là, tu penses probablement au bon vieux cast à la C : (int)x. Ça marche ? Oui. C'est sûr ? Non. Professionnel ? Encore moins.



En C++, il existe quatre opérateurs de conversion intégrés, et chacun résout un problème spécifique : static_cast, dynamic_cast, const_cast et reinterpret_cast. Les utiliser correctement, c'est écrire un code qui non seulement fonctionne, mais qui est aussi compréhensible pour les autres développeurs. Et en plus, qui ne plante pas à l'exécution avec des erreurs mystérieuses.



Dans ce tutoriel, nous allons décortiquer chaque cast avec des exemples concrets, comprendre quand les utiliser, et quand il vaut mieux ne pas caster du tout. C'est parti !



static_cast : ton ami fiable pour les conversions courantes



static_cast est le cast le plus populaire et le plus sûr. Il est utilisé pour les conversions explicites entre types apparentés : types numériques, pointeurs vers le haut/bas dans une hiérarchie d'héritage (sans vérification à l'exécution), énumérations vers entiers et inversement.



Quand utiliser static_cast ?

  • Conversion de int en double (et inversement).
  • Conversion de pointeurs au sein d'une même hiérarchie de classes (upcast — sûr, downcast — il faut être certain).
  • Conversion de void* vers un type spécifique.
  • Appel de constructeurs explicites ou d'opérateurs de conversion.


Exemple :

double pi = 3.14159;int approx = static_cast<int>(pi); // 3

class Base { public: virtual ~Base() = default; };class Derived : public Base { public: void foo() {} };

Base* b = new Derived;Derived* d = static_cast<Derived*>(b); // OK, mais sans vérificationd->foo();delete b;


Important : static_cast n'effectue pas de vérification de type à l'exécution. Si tu es sûr que l'objet est vraiment de ce type, utilise-le. Sinon, regarde du côté de dynamic_cast.



dynamic_cast : downcast sécurisé avec vérification



dynamic_cast est le seul cast qui fonctionne uniquement avec des classes polymorphes (doit avoir au moins une fonction virtuelle). Il vérifie à l'exécution si la conversion de pointeur/référence peut être effectuée en toute sécurité. Si ce n'est pas le cas, il retourne nullptr (pour les pointeurs) ou lance std::bad_cast (pour les références).



Quand utiliser dynamic_cast ?

  • Quand tu n'es pas sûr que l'objet soit vraiment du type dérivé.
  • Lorsque tu travailles avec des conteneurs hétérogènes (par exemple, un vector de Base*).
  • Dans les patrons de conception (par exemple, Visitor).


Exemple :

class Base { public: virtual ~Base() = default; };class Derived : public Base { public: void specific() {} };class Other : public Base {};

vector<Base*> objects = {new Derived, new Other, new Derived};

for (Base* obj : objects) { Derived* d = dynamic_cast<Derived*>(obj); if (d) { d->specific(); // sûr uniquement pour Derived }}


Inconvénient : dynamic_cast est plus lent que static_cast, car il nécessite RTTI (Run-Time Type Information). Ne l'utilise pas de manière excessive dans les sections critiques pour les performances.



const_cast : quand il faut enlever la constance (mais avec prudence !)



const_cast est le seul cast qui peut supprimer (ou ajouter) les qualificateurs cv (const, volatile). Ça semble cool, mais en pratique, on l'utilise rarement et seulement dans des cas extrêmes.



Pourquoi en a-t-on besoin ? Parfois, tu reçois une référence constante vers un objet, mais tu dois appeler une ancienne fonction qui n'est pas marquée const, même si elle ne modifie pas l'objet. Ou lors de l'utilisation de bibliothèques C.



Exemple (correct) :

void printInt(const int* p) {    // ancien                

Blogs

Book Recommendations