Partager via


Transtypage

En C++, si une classe est dérivée d’une classe de base contenant une ou plusieurs fonctions virtuelles, un pointeur vers ce type de classe de base peut être utilisé pour appeler des fonctions virtuelles dans l’objet de classe dérivé. Une classe contenant des fonctions virtuelles est parfois appelée une classe polymorphe.

Diagramme d’une hiérarchie de classes où C dérive de B, qui dérive d’A.
Hiérarchie de classes

Un objet de type C peut être visualisé comme suit :

Diagramme de la classe C avec des sous-objets B et A.
Classe C avec sous-objets B et A

Étant donné une instance de classe C, il existe un sous-objet B et un sous-objet A. L'instance de C, avec les sous-objets A et B forme l'objet complet.

Puisque qu’une classe dérivée contient complètement les définitions de toutes les classes de base à partir desquelles elle est dérivée, il est sûr de convertir un pointeur vers l’une de ses classes de base (opération souvent appelée upcast). Étant donné un pointeur vers une classe de base, il peut être pertinent de convertir ce pointeur en une instance d’une classe dérivée (également appelée downcast).

À l’aide d’informations de type d’exécution, il est possible de vérifier si un pointeur pointe réellement vers un objet complet et peut être converti en toute sécurité pour pointer vers un autre objet de sa hiérarchie. L’opérateur dynamic_cast effectue une vérification au moment de l’exécution pour s’assurer que l’opération est sécurisée. Il est préférable de concevoir votre hiérarchie de classes afin de pouvoir utiliser des fonctions virtuelles pour éviter tout besoin de downcasting. Toutefois, si vous devez effectuer un downcast, utilisez dynamic_cast pour vous assurer que l’opération est sécurisée.

Pour la conversion de types non polymorphiques, vous pouvez utiliser l’opérateur static_cast (cette rubrique explique la différence entre les conversions de cast statiques et dynamiques, et quand il est approprié d’utiliser chacune).

L’exemple suivant montre l’utilisation de dynamic_cast et static_cast :

#include <iostream>

class Base {
public:
    virtual void print() { std::cout << "Base\n"; }
};

class Derived1 : public Base {
public:
    void print() override { std::cout << "Derived1\n"; }
};

class Derived2 : public Base {
public:
    void print() override { std::cout << "Derived2\n"; }
};

class MostDerived : public Derived1, public Derived2 {
public:
    void print() override { std::cout << "MostDerived\n"; }
};

int main() {
    MostDerived md;
    Base* b1 = static_cast<Derived1*>(&md); // Upcast to Derived1 is safe
    Base* b2 = static_cast<Derived2*>(&md); // Upcast to Derived2 is safe

    // Downcast to MostDerived is ambiguous and unsafe
    // MostDerived* md1 = static_cast<MostDerived*>(b1); // This won't compile
    // MostDerived* md2 = static_cast<MostDerived*>(b2); // This won't compile

    // Correct way to downcast in this situation
    MostDerived* md1 = dynamic_cast<MostDerived*>(b1); // This is safe
    MostDerived* md2 = dynamic_cast<MostDerived*>(b2); // This is safe

    md1->print(); // Prints "MostDerived"
    md2->print(); // Prints "MostDerived"

    return 0;
}

Cette section couvre les sujets suivants :

Voir aussi

Expressions