Cast (C++/CX)

Quattro diversi operatori cast si applicano ai tipi di Windows Runtime: operatore static_cast, operatore dynamic_cast, operatore safe_cast e operatore reinterpret_cast. safe_cast e static_cast generare un'eccezione quando non è possibile eseguire la conversione; static_cast Operator esegue anche il controllo dei tipi in fase di compilazione. dynamic_cast restituisce nullptr se risulta impossibile convertire il tipo. Sebbene reinterpret_cast restituisca un valore non Null, potrebbe non essere valido. Per questo motivo, è consigliabile non utilizzare reinterpret_cast a meno che tu non sappia che il cast riuscirà. È inoltre consigliabile non usare cast di tipo C nel codice C++/CX perché sono identici a reinterpret_cast.

Anche il compilatore e il runtime eseguono cast impliciti, ad esempio, nelle operazioni di boxing quando un tipo di valore o un tipo incorporato viene passato come argomento a un metodo il cui tipo di parametro è Object^. In teoria, un cast implicito non deve mai generare un'eccezione in fase di esecuzione. Se il compilatore non è in grado di eseguire una conversione implicita, genera un errore in fase di compilazione.

Windows Runtime è un'astrazione su COM, che usa codici di errore HRESULT anziché eccezioni. In genere Platform::InvalidCastException indica un errore COM di basso livello di tipo E_NOINTERFACE.

static_cast

static_cast viene controllato in fase di compilazione per determinare se vi sia una relazione di ereditarietà tra i due tipi. Il cast causa un errore del compilatore se i tipi non sono correlati.

static_cast in una classe di riferimento causa anche l'esecuzione di un controllo in fase di esecuzione. static_cast in una classe di riferimento può superare la verifica in fase di compilazione ma avere comunque esito negativo in fase di esecuzione. In questo caso viene generata Platform::InvalidCastException . In genera non è necessario gestire queste eccezioni perché quasi sempre indicano errori di programmazione che puoi eliminare durante le fasi di sviluppo e test.

Utilizza static_cast se il codice dichiara in modo esplicito una relazione tra due tipi e sei quindi certo che il cast funzionerà.

    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'operatore safe_cast fa parte di Windows Runtime. Esegue un controllo del tipo di runtime e genera Platform::InvalidCastException se la conversione non riesce. Usare safe_cast quando un errore di runtime indica una condizione eccezionale. Lo scopo principale di safe_cast è identificare gli errori di programmazione durante le fasi di sviluppo e test nel punto in cui si verificano. Non è necessario gestire l'eccezione poiché l'eccezione non gestita stessa identifica il punto di errore.

Utilizza safe_cast se il codice non dichiara la relazione ma sei sicuro che il cast funzionerà.

    // 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

Usare dynamic_cast quando si esegue il cast di un oggetto (in particolare, un hat ^) a un tipo più derivato, si prevede che l'oggetto di destinazione potrebbe talvolta essere nullptr o che il cast potrebbe avere esito negativo e si vuole gestire tale condizione come percorso di codice normale anziché un'eccezione. Ad esempio, nel modello di progetto App vuota (Windows universale), il OnLaunched metodo in app.xaml.cpp usa dynamic_cast per verificare se la finestra dell'app contiene contenuto. Non è un errore se non ha contenuto; è una condizione prevista. Windows::Current::Content è Windows::UI::XAML::UIElement e la conversione viene eseguita a un Windows::UI.XAML::Controls::Frame, ovvero un tipo più derivato nella gerarchia dell'ereditarietà.

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();
        // ...
    }
}

Un altro uso di dynamic_cast è la ricerca di Object^ per determinare se contiene un tipo di valore boxed. In questo caso, si tenta dynamic_cast<Platform::Box> o dynamic_cast<Platform::IBox>.

dynamic_cast e riferimenti traccia (%)

È anche possibile applicare un oggetto dynamic_cast a un riferimento di rilevamento, ma in questo caso il cast si comporta come safe_cast. Genera Platform::InvalidCastException in caso di errore perché un riferimento traccia non può avere un valore nullptr.

reinterpret_cast

È consigliabile non utilizzare reinterpret_cast perché non viene eseguito un controllo né in fase di compilazione né di esecuzione. Nel peggiore dei casi, un reinterpret_cast rende possibile che gli errori di programmazione non siano rilevati in fase di sviluppo e causi errori sottili o irreversibili nel comportamento del programma. Pertanto, è consigliabile usare reinterpret_cast solo nei rari casi in cui devi eseguire il cast tra tipi non correlati e sai che il cast sarà completato. Un esempio di uso raro consiste nel convertire un tipo Windows Runtime nel tipo ABI sottostante. Ciò significa che si assume il controllo del conteggio dei riferimenti per l'oggetto. A tale scopo, è consigliabile utilizzare il puntatore intelligente ComPtr Class . In caso contrario, è necessario chiamare espressamente Release sull'interfaccia. Il seguente esempio mostra come si possa eseguire il cast di una classe di riferimento in IInspectable*.

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

Se usi reinterpret_cast per eseguire la conversione da un'interfaccia di Windows Runtime a un'altra, fai in modo che l'oggetto venga rilasciato due volte. Pertanto, usare questo cast solo quando si esegue la conversione in un'interfaccia delle estensioni del componente non C++.

Tipi ABI.

  • I tipi di ABI risiedono nelle intestazioni in Windows SDK. Le intestazioni sono convenientemente denominate in base allo spazio dei nomi, ad esempio windows.storage.h.

  • I tipi ABI risiedono nell'ABI di uno spazio dei nomi speciale, ad esempio ABI::Windows::Storage::Streams::IBuffer*.

  • Le conversioni tra un tipo di interfaccia Windows Runtime e il tipo ABI equivalente sono sempre sicure, IBuffer^ ovvero in ABI::IBuffer*.

  • Una classe di Windows Runtime deve sempre essere convertita in IInspectable* o nella relativa interfaccia predefinita, se nota.

  • Dopo la conversione in tipi ABI, diventi proprietario della durata del tipo ed è necessario seguire le regole COM. È consigliabile utilizzare WRL::ComPtr per semplificare la gestione della durata dei puntatori ABI.

Nella tabella seguente sono riepilogati i casi in cui è possibile utilizzare reinterpret_cast. In ogni caso, il cast è sicuro in entrambe le direzioni.

Cast da, cast a Cast a, cast da
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^*

Vedi anche