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 Opérateur effectue également la vérification du type au moment de la compilation. 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 de 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_cast
en 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^* |