Udostępnij za pośrednictwem


Rzutowanie (C++/CX)

Cztery różne operatory rzutowania mają zastosowanie do typów środowisko wykonawcze systemu Windows: operator static_cast, operator dynamic_cast, operator safe_cast i operator reinterpret_cast. safe_cast i static_cast zgłasza wyjątek, gdy nie można wykonać konwersji; static_cast Operator wykonuje również sprawdzanie typu kompilatora czasu. dynamic_cast Metoda zwraca wartość nullptr , jeśli nie można przekonwertować typu. Chociaż reinterpret_cast zwraca wartość inną niż null, może być nieprawidłowa. Z tego powodu zalecamy, aby nie używać reinterpret_cast , chyba że wiadomo, że rzut zakończy się powodzeniem. Ponadto zalecamy, aby nie używać rzutów w stylu C w kodzie C++/CX, ponieważ są one identyczne z reinterpret_cast.

Kompilator i środowisko uruchomieniowe również wykonują niejawne rzutowania — na przykład w operacjach boksu, gdy typ wartości lub typ wbudowany są przekazywane jako argumenty do metody, której typem parametru jest Object^. Teoretycznie niejawne rzutowanie nigdy nie powinno powodować wyjątku w czasie wykonywania; Jeśli kompilator nie może wykonać niejawnej konwersji, zgłasza błąd w czasie kompilacji.

środowisko wykonawcze systemu Windows to abstrakcja modelu COM, która używa kodów błędów HRESULT zamiast wyjątków. Ogólnie rzecz biorąc, platforma::InvalidCastException wskazuje błąd COM niskiego poziomu E_NOINTERFACE.

static_cast

Element static_cast jest sprawdzany w czasie kompilacji, aby określić, czy istnieje relacja dziedziczenia między dwoma typami. Rzutowanie powoduje błąd kompilatora, jeśli typy nie są powiązane.

Element static_cast w klasie ref powoduje również wykonanie sprawdzania czasu wykonywania. Klasa static_cast ref może przejść weryfikację czasu kompilacji, ale nadal kończy się niepowodzeniem w czasie wykonywania. W tym przypadku Platform::InvalidCastException zgłaszany jest błąd. Ogólnie rzecz biorąc, nie trzeba obsługiwać tych wyjątków, ponieważ prawie zawsze wskazują one błędy programistyczne, które można wyeliminować podczas programowania i testowania.

Użyj static_cast , jeśli kod jawnie deklaruje relację między dwoma typami, a zatem masz pewność, że rzutowanie powinno działać.

    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

Operator safe_cast jest częścią środowisko wykonawcze systemu Windows. Wykonuje sprawdzanie typu czasu wykonywania i zgłasza Platform::InvalidCastException błąd, jeśli konwersja nie powiedzie się. Użyj safe_cast , gdy błąd czasu wykonywania wskazuje wyjątkowy warunek. Podstawowym celem safe_cast jest pomoc w identyfikowaniu błędów programowania w fazach programowania i testowania w momencie ich wystąpienia. Nie musisz obsługiwać wyjątku, ponieważ sam nieobsługiwany wyjątek identyfikuje punkt awarii.

Użyj safe_cast, jeśli kod nie deklaruje relacji, ale masz pewność, że rzutowanie powinno działać.

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

Należy użyć dynamic_cast podczas rzutowania obiektu (w szczególności kapelusza ^) do bardziej pochodnego typu, oczekuje się, że obiekt docelowy może czasami być nullptr lub że rzutowanie może zakończyć się niepowodzeniem i chcesz obsłużyć ten warunek jako zwykłą ścieżkę kodu zamiast wyjątku. Na przykład w szablonie OnLaunched projektu Pusta aplikacja (uniwersalny system Windows) metoda w app.xaml.cpp używa dynamic_cast metody do testowania, czy okno aplikacji ma zawartość. Nie jest to błąd, jeśli nie ma zawartości; jest to oczekiwany warunek. Windows::Current::Content jest elementem Windows::UI::XAML::UIElement , a konwersja jest na Windows::UI.XAML::Controls::Frame, który jest bardziej pochodnym typem w hierarchii dziedziczenia.

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

Innym zastosowaniem dynamic_cast metody jest sondowania elementu w Object^ celu określenia, czy zawiera typ wartości pola. W takim przypadku próbujesz podjąć próbę lub dynamic_cast<Platform::Box> .dynamic_cast<Platform::IBox>

dynamic_cast i odwołania do śledzenia (%)

Można również zastosować element dynamic_cast do odwołania do śledzenia, ale w tym przypadku rzutowanie zachowuje się jak safe_cast. Zgłasza Platform::InvalidCastException błąd, ponieważ odwołanie do śledzenia nie może mieć wartości nullptr.

reinterpret_cast

Zalecamy, aby nie używać reinterpret_cast , ponieważ nie jest przeprowadzane ani sprawdzanie czasu kompilacji, ani sprawdzanie czasu wykonywania. W najgorszym przypadku możliwe jest, reinterpret_cast aby błędy programowania nie są wykrywane w czasie programowania i powodować subtelne lub katastrofalne błędy w zachowaniu programu. Dlatego zalecamy użycie reinterpret_cast tylko w tych rzadkich przypadkach, gdy należy rzutować między niepowiązanymi typami i wiedzieć, że rzutowanie zakończy się powodzeniem. Przykładem rzadkiego użycia jest przekonwertowanie typu środowisko wykonawcze systemu Windows na jego podstawowy typ ABI — oznacza to, że przejmujesz kontrolę nad liczeniem odwołań dla obiektu. W tym celu zalecamy użycie inteligentnego wskaźnika klasy ComPtr. W przeciwnym razie należy w szczególności wywołać metodę Release w interfejsie. W poniższym przykładzie pokazano, jak można rzutować klasę ref na klasę IInspectable*.

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

Jeśli używasz reinterpret_cast metody do konwersji z jednego interfejsu środowisko wykonawcze systemu Windows na inny, obiekt zostanie zwolniony dwa razy. W związku z tym należy używać tego rzutowania tylko podczas konwertowania na interfejs rozszerzeń składników innych niż C++.

Typy ABI

  • Typy ABI działają w nagłówkach w zestawie Windows SDK. Wygodnie nagłówki są nazwane po przestrzeniach nazw — na przykład windows.storage.h.

  • Typy ABI działają w specjalnej przestrzeni nazw ABI — na przykład ABI::Windows::Storage::Streams::IBuffer*.

  • Konwersje między typem interfejsu środowisko wykonawcze systemu Windows a jego równoważnym typem ABI są zawsze bezpieczne — czyli IBuffer^ do ABI::IBuffer*.

  • Jeśli jest to znane, klasa środowisko wykonawcze systemu Windows powinna być zawsze konwertowana na IInspectable* lub jej interfejs domyślny.

  • Po przekonwertowaniu na typy ABI będziesz właścicielem okresu istnienia typu i musisz postępować zgodnie z regułami MODELU COM. Zalecamy, aby WRL::ComPtr uprościć zarządzanie okresem istnienia wskaźników ABI.

W poniższej tabeli przedstawiono podsumowanie przypadków, w których można bezpiecznie używać programu reinterpret_cast. W każdym przypadku obsada jest bezpieczna w obu kierunkach.

Rzutowanie z, rzutowanie do Rzutowanie do, rzutowanie z
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^*

Zobacz też