Outils pour utilisateurs

Outils du site


lang:cpp:cast

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]);
}

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
lang/cpp/cast.1583277888.txt.gz · Dernière modification : 2020/03/04 00:24 de root