Dela via


Gjutning (C++/CX)

Fyra olika typomvandlingsoperatorer appliceras på Windows Runtime-typer: static_cast Operator, dynamic_cast Operator, safe_cast Operator och reinterpret_cast Operator. safe_cast och static_cast utlöser ett undantag när konverteringen inte kan utföras. static_cast Operator utför också kontroll av kompileringstidstyp. dynamic_cast returnerar nullptr om det inte går att konvertera typen. Även om reinterpret_cast returnerar ett värde som inte är null kan det vara ogiltigt. Därför rekommenderar vi att du inte använder reinterpret_cast om du inte vet att rollbesättningen kommer att lyckas. Dessutom rekommenderar vi att du inte använder C-formateringar i C++/CX-koden eftersom de är identiska med reinterpret_cast.

Kompilatorn och körningstiden utför också implicita typomvandlingar, till exempel vid boxingoperationer när en värdetyp eller standardtyp skickas som argument till en metod vars parametertyp är Object^. I teorin bör en implicit typomvandling aldrig orsaka ett undantag vid körning; om kompilatorn inte kan utföra en implicit konvertering, uppstår ett fel vid kompilering.

Windows Runtime är en abstraktion över COM, som använder HRESULT-felkoder i stället för undantag. I allmänhet anger Platform::InvalidCastException ett COM-fel på låg nivå för E_NOINTERFACE.

static_cast

A static_cast kontrolleras vid kompileringstillfället för att avgöra om det finns en arvsrelation mellan de två typerna. Typomvandlingen orsakar ett kompilatorfel om typerna inte är relaterade.

En static_cast på en referensklass gör också att en körningskontroll utförs. En static_cast på en referensklass kan godkänna verifieringen vid kompileringstiden men ändå misslyckas vid körning; i det här fallet kastas en Platform::InvalidCastException. I allmänhet behöver du inte hantera dessa undantag eftersom de nästan alltid indikerar programmeringsfel som du kan eliminera under utveckling och testning.

Använd static_cast om koden uttryckligen deklarerar en relation mellan de två typerna, och du därför är säker på att casten ska fungera.

    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

Operatorn safe_cast är en del av Windows Runtime. Den utför en körningstypkontroll och utlöser en Platform::InvalidCastException om konverteringen misslyckas. Använd safe_cast när ett körningsfel indikerar ett exceptionellt villkor. Det främsta syftet med safe_cast är att hjälpa till att identifiera programmeringsfel under utvecklings- och testfaserna vid den punkt där de inträffar. Du behöver inte hantera undantaget eftersom själva det ohanterade undantaget identifierar felpunkten.

Använd safe_cast om koden inte deklarerar relationen, men du är säker på att typkonverteringen ska fungera.

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

Använd dynamic_cast när du omvandlar ett objekt (mer specifikt en hatt ^) till en mer härledd typ, du förväntar dig antingen att målobjektet ibland kan vara nullptr eller att gjutningen misslyckas, och du vill hantera det villkoret som en vanlig kodsökväg i stället för ett undantag. I till exempel projektmallen Tom app (Universell Windows) använder metoden i app.xaml.cpp OnLaunched för att testa om appfönstret har innehåll. Det är inte ett fel om det inte har innehåll. det är ett förväntat villkor. Windows::Current::Content är en Windows::UI::XAML::UIElement och konverteringen är till en Windows::UI.XAML::Controls::Frame, som är en mer härledd typ i arvshierarkin.

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

En annan användning av dynamic_cast är att undersöka Object^ för att avgöra om det innehåller en kapslad värdetyp. I det här fallet försöker du en dynamic_cast<Platform::Box> eller en dynamic_cast<Platform::IBox>.

dynamic_cast och spårningsreferenser (%)

Du kan också använda en dynamic_cast för en spårningsreferens, men i det här fallet fungerar typomvandlingen som safe_cast. Den kastar Platform::InvalidCastException vid misslyckande eftersom en spårningsreferens inte kan ha värdet nullptr.

reinterpret_cast

Vi rekommenderar att du inte använder reinterpret_cast eftersom varken en kompileringstidskontroll eller en körningskontroll utförs. I värsta fall gör en reinterpret_cast det möjligt för programmeringsfel att gå oidentifierade vid utvecklingstid och orsaka subtila eller katastrofala fel i programmets beteende. Därför rekommenderar vi att du endast använder reinterpret_cast i de sällsynta fall när du måste typomvandla mellan orelaterade typer och du är säker på att omvandlingen kommer att lyckas. Ett exempel på en sällsynt användning är att konvertera en Windows Runtime-typ till dess underliggande ABI-typ, vilket innebär att du tar kontroll över referensräkningen för objektet. För att göra detta rekommenderar vi att du använder den smarta pekaren ComPtr Class . Annars måste du specifikt anropa Release i gränssnittet. I följande exempel visas hur en referensklass kan omvandlas till en IInspectable*.

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

Om du använder reinterpret_cast för att konvertera från ett Windows Runtime-gränssnitt till ett annat orsakar du att objektet släpps två gånger. Använd därför endast den här casten när du konverterar till ett gränssnitt som inte är C++-komponenttillägg.

ABI-typer

  • ABI-typerna finns i rubriker i Windows SDK. Praktiskt nog namnges rubrikerna efter namnrymderna, till exempel windows.storage.h.

  • ABI-typer finns i ett särskilt namnområde ABI, till exempel ABI::Windows::Storage::Streams::IBuffer*.

  • Konverteringar mellan en Windows Runtime-gränssnittstyp och dess motsvarande ABI-typ är alltid säkra, IBuffer^ dvs. till ABI::IBuffer*.

  • En Windows Runtime-klass ska alltid konverteras till IInspectable* eller dess standardgränssnitt, om det är känt.

  • När du har konverterat till ABI-typer äger du typens livslängd och måste följa COM-reglerna. Vi rekommenderar att du använder WRL::ComPtr för att förenkla livslängdshanteringen av ABI-pekare.

I följande tabell sammanfattas de fall där det är säkert att använda reinterpret_cast. I varje fall är gipset säkert i båda riktningarna.

Skicka från, skicka till Omvandla till, omvandla från
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^*

Se även