Effectuer un cast (C++/CX)

Quatre opérateurs de cast différents s’appliquent aux types Windows Runtime : opérateur static_cast, opérateur dynamic_cast, opérateur safe_cast et opérateur reinterpret_cast. safe_cast et static_cast lèvez une exception lorsque la conversion ne peut pas être effectuée ; static_cast Operator effectue également un type de compilation case activée ing. dynamic_cast retourne nullptr s'il ne réussit pas à convertir le type. Même si reinterpret_cast retourne une valeur non null, elle peut ne pas être valide. C'est la raison pour laquelle nous vous recommandons de ne pas utiliser reinterpret_cast , sauf si vous savez que le cast va réussir. En outre, nous vous recommandons de ne pas utiliser de casts de style C dans votre code C++/CX, car ils sont identiques à reinterpret_cast.

Le compilateur et le runtime exécutent également des casts implicites, par exemple, dans les opérations de boxing lorsqu'un type valeur ou un type intégré sont passés en tant qu'arguments à une méthode dont le type de paramètre est Object^. En théorie, un cast implicite ne doit jamais générer une exception au moment de l'exécution. Si le compilateur ne peut pas effectuer une conversion implicite, il déclenche une erreur au moment de la compilation.

Windows Runtime est une abstraction sur COM, qui utilise des codes d’erreur HRESULT au lieu d’exceptions. En général, Platform::InvalidCastException indique une erreur COM de bas niveau d'E_NOINTERFACE.

static_cast

static_cast est vérifié au moment de la compilation pour déterminer s'il existe une relation d'héritage entre les deux types. Le cast provoque une erreur de compilation si les types ne sont pas liés.

static_cast sur une classe ref entraîne également une vérification au moment de l'exécution. static_cast sur une classe de référence peut passer la vérification du moment de compilation mais encore échouer au moment de l'exécution. Dans ce cas, Platform::InvalidCastException est levée. En général, vous n'avez pas à gérer ces exceptions, car elles indiquent presque toujours des erreurs de programmation que vous pouvez éliminer au cours du développement et des tests.

Utilisez static_cast si le code déclare explicitement une relation entre les deux types, et si vous êtes certain que le cast doit fonctionner.

    interface class A{};
    public ref class Class1 sealed : A { };
    // ...
    A^ obj = ref new Class1(); // Class1 is an A
    // You know obj is a Class1. The compiler verifies that this is possible, and in C++/CX a run-time check is also performed.
    Class1^ c = static_cast<Class1^>(obj);

safe_cast

L’opérateur safe_cast fait partie de Windows Runtime. Il effectue une vérification de type au moment de l'exécution et lève une Platform::InvalidCastException si la conversion échoue. Utilisez safe_cast lorsqu’un échec au moment de l’exécution indique une condition exceptionnelle. L’objectif principal de safe_cast est d’aider à identifier les erreurs de programmation pendant les phases de développement et de test au moment où elles se produisent. Vous ne devez pas gérer l'exception, car l'exception non gérée elle-même identifie le point de défaillance.

Utilisez safe_cast si le code ne déclare pas la relation mais que vous avez la certitude que le cast doit fonctionner.

    // A and B are not related
    interface class A{};
    interface class B{};
    public ref class Class1 sealed : A, B { };
    // ...
    A^ obj = ref new Class1();

    // You know that obj's backing type implements A and B, but
    // the compiler can't tell this by comparing A and B. The run-time type check succeeds.
    B^ obj2 = safe_cast<B^>(obj);

dynamic_cast

Utilisez dynamic_cast quand vous castez un objet (plus précisément, un chapeau ^) en un type plus dérivé, vous vous attendez à ce que l’objet cible puisse parfois être nullptr ou que le cast peut échouer et que vous souhaitez gérer cette condition en tant que chemin de code standard au lieu d’une exception. Par exemple, dans le modèle de projet Application vide (Windows universel), la OnLaunched méthode dans app.xaml.cpp utilise dynamic_cast pour tester si la fenêtre de l’application a du contenu. Il ne s’agit pas d’une erreur s’il n’a pas de contenu ; il s’agit d’une condition attendue. Windows::Current::Content est un Windows::UI::XAML::UIElement et est converti en un Windows::UI.XAML::Controls::Frame, qui est un type plus dérivé dans la hiérarchie d'héritage.

void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ args)
{
    auto rootFrame = dynamic_cast<Frame^>(Window::Current->Content);

    // Do not repeat app initialization when the window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        // Create a Frame to act as the navigation context and associate it with
        // a SuspensionManager key
        rootFrame = ref new Frame();
        // ...
    }
}

Une autre utilisation de dynamic_cast est de détecter un Object^ pour déterminer s'il contient un type valeur boxed. Dans ce cas, vous tentez une dynamic_cast<Platform::Box> ou une dynamic_cast<Platform::IBox>.

dynamic_cast et références de suivi (%)

Vous pouvez également appliquer une dynamic_cast référence de suivi, mais dans ce cas, le cast se comporte comme safe_cast. Il lève une Platform::InvalidCastException en cas d'échec, car une référence de suivi ne peut pas avoir la valeur nullptr.

reinterpret_cast

Nous vous recommandons de ne pas utiliser reinterpret_cast , car aucune vérification n'est effectuée, que ce soit au moment de la compilation ou de l'exécution. Dans le pire des cas, il reinterpret_cast est possible que les erreurs de programmation ne se détectent pas au moment du développement et provoquent des erreurs subtiles ou catastrophiques dans le comportement de votre programme. Par conséquent, nous vous recommandons d'utiliser reinterpret_cast uniquement dans les rares cas où vous devez effectuer un cast entre des types non liés et vous savez que le cast réussit. Un exemple d’utilisation rare consiste à convertir un type Windows Runtime en son type ABI sous-jacent, ce qui signifie que vous prenez le contrôle du comptage de référence pour l’objet. C'est la raison pour laquelle nous vous recommandons d'utiliser le pointeur intelligent ComPtr Class . Sinon, vous devez appeler spécifiquement Release sur l'interface. L'exemple suivant montre comment une classe de référence peut faire l'objet d'un cast en une IInspectable*.

#include <wrl.h>
using namespace Microsoft::WRL;
auto winRtObject = ref new SomeWinRTType();
ComPtr<IInspectable> inspectable = reinterpret_cast<IInspectable*>(winRtObject);
// ...

Si vous utilisez reinterpret_cast pour convertir d’une interface Windows Runtime vers une autre, vous entraînez la libération de l’objet deux fois. Par conséquent, utilisez ce cast uniquement lorsque vous effectuez une conversion en interface d’extensions de composant non-C++.

Types ABI.

  • Les types ABI se trouvent dans les en-têtes du Kit de développement logiciel (SDK) Windows. Pour des raisons de commodité, les en-têtes sont nommés d'après le nom des espaces de noms, par exemple, windows.storage.h.

  • Les types ABI se trouvent dans une ABI d'espace de noms spéciale, par exemple, ABI::Windows::Storage::Streams::IBuffer*.

  • Les conversions entre un type d’interface Windows Runtime et son type ABI équivalent sont toujours sécurisées, c’est-à-dire en IBuffer^ ABI::IBuffer*.

  • Une classe Windows Runtime doit toujours être convertie en IInspectable* ou son interface par défaut, si elle est connue.

  • Après la conversion en types ABI, vous possédez la durée de vie du type et vous devez suivre les règles COM. Nous vous recommandons d'utiliser WRL::ComPtr pour simplifier la gestion de la durée de vie des pointeurs ABI.

Le tableau suivant récapitule les cas dans lesquels il est possible d'utiliser reinterpret_casten toute sécurité. Dans tous les cas, le cast est sécurisé dans les deux sens.

Cast de, cast vers Cast vers, cast à partir de
HSTRING String^
HSTRING* String^*
IInspectable* Object^
IInspectable** Object^*
IInspectable-derived-type* same-interface-from-winmd^
IInspectable-derived-type** same-interface-from-winmd^*
IDefault-interface-of-RuntimeClass* same-RefClass-from-winmd^
IDefault-interface-of-RuntimeClass** same-RefClass-from-winmd^*

Voir aussi