Ceci est une ancienne révision du document !
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<float>(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<C *>(&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<D *>(b); // d == nullptr d = dynamic_cast<D *>(b); return d == nullptr; }
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<char *>(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<short*>(&b[0]); }
Les problèmes
Cast vers un parent d'un héritage multiple
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<Parent2*>(this);
Il faut faire (ci-dessous). Puis un cast
naturel se fera de Enfant
vers Parent2
.
Parent2* p = static_cast<Enfant*>(this);
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<B *>(&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