Prochaine révision | Révision précédente |
lang:cpp:cast [2020/03/04 00:24] – Création root | lang:cpp:cast [2024/11/12 12:45] (Version actuelle) – Modification des options de compilation des sanitizers root |
---|
</code> | </code> |
| |
| 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é. |
| |
| <code c++> |
| #include <typeinfo> |
| |
| class A { |
| public: |
| virtual ~A() = default; |
| }; |
| |
| class B : public A {}; |
| |
| class C {}; |
| |
| int main() { |
| B b; |
| A& a = dynamic_cast<A&>(b); |
| try { |
| C& c = dynamic_cast<C&>(b); |
| } catch (const std::bad_cast&) { |
| return 1; |
| } |
| return 0; |
| } |
| </code> |
| |
| [[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=== |
| |
</code> | </code> |
| |
====sanitizer==== | ====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. |
| <code cpp> |
| Parent2* p = reinterpret_cast<Parent2*>(this); |
| </code> |
| |
| Il faut faire (ci-dessous). Puis un ''cast'' naturel se fera de ''Enfant'' vers ''Parent2''. |
| <code cpp> |
| Parent2* p = static_cast<Enfant*>(this); |
| </code> |
| |
| ===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. | 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. |
Les classes A et B étant identiques, il est normal que le programme s'exécute correctement. | 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'' : | Mais avec un sanitizer ''clang++ -fsanitize=undefined -fno-sanitize-recover=all 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' | main.cc:17:13: runtime error: member call on address 0x7ffc03ba2878 which does not point to an object of type 'B' |