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^
doABI::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^* |