====Les quatre types de cast==== En C++, on utilise plus un cast entre parenthèse, on utilise ''static_cast'', ''dynamic_cast'', ''const_cast'' ou ''reinterpret_cast''. ===static_cast=== ''static_cast'' peut être utilisé pour caster les types primitifs entre eux. double d = 0.1; // Perte explicite de précision float f = static_cast(d); ''static_cast'' est aussi utilisé pour caster une classe parent vers un type enfant. struct B { int f() { return 2; } }; struct C : public B { int f() { return 3; } }; int main() { B b; C *c = static_cast(&b); return c->f(); } ===dynamic_cast=== ''dynamic_cast'' permet de vérifier que le ''static_cast'' est possible. Il est nécessaire que la classe soit polymorphique (au moins une méthode virtuelle). struct B { virtual ~B() = default; int f() { return 2; } }; struct C : public B { int f() { return 3; } }; struct D : public B { int f() { return 3; } }; int main() { C c; B *b = &c; // d != nullptr D *d = static_cast(b); // d == nullptr d = dynamic_cast(b); return d == nullptr; } Il est aussi possible d'utiliser ''dynamic_cast'' avec des références. En cas d'échec, une exception ''std::bad_cast'' sera généré. #include class A { public: virtual ~A() = default; }; class B : public A {}; class C {}; int main() { B b; A& a = dynamic_cast(b); try { C& c = dynamic_cast(b); } catch (const std::bad_cast&) { return 1; } return 0; } [[https://www.ibm.com/docs/en/i/7.2?topic=operator-dynamic-casts-references|Dynamic Casts with References]] {{ :lang:cpp:cast:dynamic_casts_with_references_-_ibm_documentation_23_06_2023_16_43_55_.html |Archive du 14/04/2021 le 23/06/2023}} ===const_cast=== ''const_cast'' sert uniquement à enlever un ''const'' à un type. const char *t = "coucou"; void f(char *tt) { // Interdit tt[0] = 1; } int main() { f(const_cast(t)); return 0; } ===reinterpret_cast=== ''reinterpret_cast'' est utilisé lorsqu'on souhaite caster un pointeur vers un autre sans rapport implicite. Son utilisation est souvent synonyme de mauvaises pratiques de codage. int main() { int b[5]; short *s = reinterpret_cast(&b[0]); } ====Les problèmes==== ===Cast vers un parent d'un héritage multiple=== {{ lang:cpp:heritage:heritage_multiple.svg |}} Depuis ''Parent1'', caster ''this'' vers ''Parent2''. Il ne faut surtout pas faire (ci-dessous). Sinon, les méthodes virtuelles (au minimum) appelleront n'importe quoi. De toute façon d'une manière générale, ''reinterpret_cast'' ne s'utilise que vers la classe la plus basse dans l'héritage. Parent2* p = reinterpret_cast(this); Il faut faire (ci-dessous). Puis un ''cast'' naturel se fera de ''Enfant'' vers ''Parent2''. Parent2* p = static_cast(this); ===reinterpret_cast sur une classe avec héritage=== Un ''static_cast'' ou un ''dynamic_cast'' ne pose pas de problème dans le cas d'héritage multiple. Par contre, un ''reinterpret_cast'' d'un ''void *'' doit toujours se faire sur la classe la plus basse (la plus enfant). Un ''void *'' ne possède aucune information du type de la classe et donc le compilateur ne sait pas comment s'en sortir. Par exemple avec les méthodes virtuelles, il ne peut pas savoir à quelle classe appartient la première méthode en tête de la ''vtable''. Il y a les mêmes problèmes avec les attributs de la classe. [[https://stackoverflow.com/questions/2379427/multiple-inheritance-unexpected-result-after-cast-from-void-to-2nd-base-class|multiple inheritance: unexpected result after cast from void * to 2nd base class]] {{ :lang:cpp:heritage:c_-_multiple_inheritance_unexpected_result_after_cast_from_void_to_2nd_base_class_-_stack_overflow_2019-12-19_2_21_51_pm_.html |Archive du 04/03/2010 le 19/12/2019}} ===Les détecters avec sanitizer=== Les sanitizer peuvent détecter les erreurs de ''static_cast'' / ''reinterpret_cast''. Il est quand même nécessaire que la classe castée soit polymorphique. struct A { virtual int f() { return 1; } }; struct B { virtual int f() { return 2; } }; struct C : public B {}; int main() { A a; B *b = reinterpret_cast(&a); return b->f(); } Les classes A et B étant identiques, il est normal que le programme s'exécute correctement. Mais avec un sanitizer ''clang++ -fsanitize=undefined main.cc -o a.out -flto -fvisibility=hidden'' : main.cc:17:13: runtime error: member call on address 0x7ffc03ba2878 which does not point to an object of type 'B' 0x7ffc03ba2878: note: object is of type 'A' fc 7f 00 00 88 4d bf 29 2b 56 00 00 78 28 ba 03 fc 7f 00 00 00 09 cf 0b 25 bc 5d 17 00 00 00 00