Pour varier un peu le contenu de mon blog (et aussi parcequ’on m’a fait des réflexions désobligeantes sur Ruby ! ;p) je ressors aujourd’hui un petit tutorial C++ que j’avais écris pour les autres membres d’un projet effectué l’année dernière (un Tamagotchi pour la petite histoire).
Alors bien sûr, vous connaissez les casts en C, ça donne quelque chose comme ça :
int a = 10 ; unsigned b = (unsigned)a ;
Seulement c’est la méthode C, et dans son immense mansuétude, Mr. Bjarne Stroustrup nous a donné 4 opérateurs standards permettant de faire tous les casts possible.
- Le static_cast<>C’est l’opérateur de cast classique, il fait une conversion statique, comme celle que j’ai écrite 3 lignes plus haut. L’équivalent en C++ est donc :
int a = 10 ; unsigned b = static_cast<unsigned>(a) ;
Rien de spécial à savoir, les conversions illégales passeront pas à la compilation, enfin la routine quoi.
- Le reinterpret_cast<>Ca c’est un cast un peu spécial mais très pratique ; il s’emploie quand vous voulez dire au compilateur de prendre un objet de type A pour un objet de type B. Il ne fait aucune conversion physique, il s’agit juste d’une indication que donne le développeur au compilateur, du genre « Je sais bien que ta fonction prend en paramètre un objet B, mais moi j’te file un objet A, et ça marche. Tu veux pas compiler, alors je réinterprète le type de mon objet pour que ça devienne un B. »
void Fun (B *Obj) { // Une fonction lambda, prenant un B* en paramètre... } // ... A* Bla = new A() ; Fun (reinterpret_cast<B*> (A)) ;A noter, les familles A et B doivent être liées (du genre A dérive de B…) sinon la compilation de marchera quand même pas.
- Le const_cast<>Super pratique le const_cast ! Il y a toujours des problèmes de conversion entre des variables normales et des variables const, c’est lourd, on se prend la tête, on essaye de mettre des variables intermédiaires, ça foire… Quand on passe d’une variable normale à une variable const, la conversion est explicite et il n’y a aucun problème, mais quand on passe d’un const à une normale, là ça craint, et ça compile pas.Enfin bref, le const_cast<> permet de s’affranchir tout simplement de ce problème.
const X* Bla = new X() ; X* Bla2 = const_cast<X*> (Bla) ;
- Le dynamic_cast<>Celui-là c’est le plus complexe, à utiliser dans des cas très précis, des problèmes insolubles autrement. Et c’est pas facile à expliquer aussi.
Je vais commencer par introduire la notion de cross_casting. Imaginez que vous avez trois classes, Bla, Prout, et la classe BlaProut qui dérive des deux autres en mêmes temps.Soit :
Bla Prout
\ /
\ /
BlaProutOu encore :
class Bla ; class Prout ; class BlaProut : public Bla, public Prout ;
Maintenant regardez bien ça va aller très vite, c’est pas de la magie mais presque. Avec un petit dynamic_cast<> je vais pouvoir obtenir un objet de Prout à partir d’un objet de Bla…
Bla *B = new BlaProut() ; // je peux le faire parceque BlaProut dérive de Bla ! Prout *P = dynamic_cast<Prout*> (B) ;
Impressionnant n’est-ce pas? Et pourquoi ça marche? Parceque c’est exactement équivalent à ceci :
Bla *B = new BlaProut() ; BlaProut *BP = dynamic_cast<BlaProut*> (B) ; // on cast un Bla* en BlaProut* Prout *P = static_cast<Prout*> (BP) ; // eh oui, ça marche !
Mais comme vous vous en doutez bien, ce genre de conversions va forcément induire des problèmes à terme. De mon côté je n’ai jamais eu à utiliser le dynamic_cast<>, et j’espère vraiment que ça n’arrivera pas de sitôt…
#1 par Stef à 26 mars 2009 - 22:41
Citation
Heiiin ? Qui a dit ça ? Oh non, c’était tellement mieux quand tu nous parlais de ce merveilleux langage qu’est le Ruby !!
Sympa le tuto sinon, on pourrait faire un projet sur les interrogations des moteurs de recherche en langage naturel avec un langage pareil…. =D
#2 par jm à 27 mars 2009 - 00:21
Citation
Interessant, je ne connaissais pas ces operateurs.
C’est bien d’avoir un billet sur ce bon vieux C++