Contrairement au C, les cast C++ sont effectués au moyen d'opérateurs spécifiques (mots-clés réservés). Le choix de ces opérateurs
dépend du type de cast, car le C++ différencie 4 types de conversion explicite. Tout d'abord, 3 opérateurs sont dédiés aux conversions
statiques (effectuées à la compilation) :
* static_cast : entre types de même famille. Il s'agit la plupart du temps d'expliciter des conversions qui auraient pu être
effectuées de manière implicite, mais souvent avec un avertissement du compilateur.
int i = 100 ;
char c = static_cast < char > ( i );
float f = 100 .0f ;
i = static_cast < int > ( f );
class A { } ;
class B : public A { } ;
B * b = new B;
A * a = static_cast < A* > ( b );
|
* reinterpret_cast : entre types de familles différentes. Il s'agit simplement de dire au compilateur "je sais que je manipule une
donnée de type X, mais on va faire comme si elle était de type Y". De ce fait aucune donnée n'est physiquement modifiée, cet opérateur
de conversion n'est qu'une indication pour le compilateur.
int i;
char * ptr = reinterpret_cast < char * > ( i );
char & ref = reinterpret_cast < char & > ( i );
double * ptr2 = reinterpret_cast < double * > ( ptr );
|
* const_cast : entre un type donné constant et le même type avec / sans les qualificateurs const ou volatile. Cet opérateur est
rarement utilisé, car :
- La conversion non-const -> const est implicite.
- La conversion const -> non-const relève en fait bien souvent d'une erreur de conception.
- Le qualificateur volatile est rarement utilisé.
class A { } ;
const A * cptr;
A * ptr = const_cast < A* > ( cptr );
A a;
const A & cref = a;
A & ref = const_cast < A& > ( cref );
|
Le C++ supporte aussi un autre type de conversion : depuis une classe parent vers une classe enfant (downcasting) ou depuis une classe
parent vers une autre classe parent (crosscasting). La classe parent doit être à usage polymorphe,
autrement dit elle doit obligatoirement comporter au moins une fonction membre virtuelle, et être manipulée au moyen d'un pointeur ou d'une référence (la virtualité
implique l'utilisation de pointeurs ou de références, voir Que signifie le mot-clé virtual ?). Ce type de cast étant dynamique (effectué à
l'exécution), il est susceptible d'échouer et de lever une exception std::bad_cast dans le cas d'une conversion de références, ou de
renvoyer NULL dans le cas d'une conversion de pointeurs.
L'opérateur associé à ce cast est dynamic_cast :
# include <iostream>
# include <string>
class A
{
public :
virtual std:: string get_type () = 0 ;
} ;
class B : public A
{
public :
virtual std:: string get_type () { return " B " ; }
} ;
class C : public A
{
public :
virtual std:: string get_type () { return " C " ; } ;
} ;
A * create_B_or_C ()
{
static int nb = 0 ;
+ + nb;
if ( nb % 2 = = 0 ) { return new B; }
return new C;
}
int main ()
{
for ( int i = 0 ; i < 5 ; + + i )
{
A * a = create_B_or_C ();
std:: cout < < " Test sur un " < < a- > get_type () < < " : " ;
B * b = dynamic_cast < B* > ( a );
if ( b = = 0 )
{
try
{
C & c = dynamic_cast < C& > ( * a );
std:: cout < < " il s'agit d'un C.\n " ;
}
catch ( const std:: bad_cast & )
{
std:: cout < < " Oups!\n " ;
}
}
else
{
std:: cout < < " il s'agit d'un B.\n " ;
}
}
}
|
dynamic_cast identifie à l'exécution le type réel de l'expression reçue au moyen des informations de type à l'exécution (RTTI).
Cette fonctionnalité doit donc être activée dans votre compilateur pour pouvoir utiliser dynamic_cast, ce qui n'est pas le cas par
défaut avec certains compilateurs (tel que VC++, voir l'option /GR).
|