Umwandlung von Typen (C++/CX)

Vier verschiedene Umwandlungsoperatoren gelten für Windows-Runtime Typen: static_cast Operator, dynamic_cast Operator, safe_cast Operator und reinterpret_cast Operator. safe_cast und static_cast lösen Sie eine Ausnahme aus, wenn die Konvertierung nicht ausgeführt werden kann; static_cast Operator führt auch die Kompilierungszeittypüberprüfung durch. dynamic_cast gibt nullptr zurück, wenn der Typ nicht umgewandelt werden kann. Obwohl reinterpret_cast einen Wert ungleich Null zurückgibt, ist er möglicherweise ungültig. Aus diesem Grund wird empfohlen, dass Sie reinterpret_cast nur verwenden, wenn Sie wissen, dass die Umwandlung folgt. Darüber hinaus wird empfohlen, keine C-Stil-Umwandlungen in Ihrem C++/CX-Code zu verwenden, da sie identisch reinterpret_castmit ihnen sind.

Der Compiler und die Laufzeit führen ebenfalls implizite Umwandlungen aus – beispielsweise bei Boxingvorgängen, wenn ein Werttyp oder ein integrierter Datentyp als Argumente an eine Methode mit dem Parametertyp Object^übergeben werden. Theoretisch sollte eine implizite Umwandlung zur Laufzeit nie Ausnahmen verursachen. Wenn der Compiler eine implizite Konvertierung nicht ausführen kann, löst dies einen Fehler zur Kompilierzeit aus.

Windows-Runtime ist eine Abstraktion über COM, die HRESULT-Fehlercodes anstelle von Ausnahmen verwendet. Im Allgemeinen gibt Platform::InvalidCastException einen COM-Fehler auf niedriger Ebene bei E_NOINTERFACE an.

static_cast

static_cast wird zur Kompilierzeit überprüft, um zu bestimmen, ob zwischen den zwei Typen eine Vererbungsbeziehung besteht. Die Umwandlung verursacht einen Compilerfehler, wenn die Typen nicht verknüpft sind.

Ein static_cast auf einer Verweisklasse bewirkt auch, dass eine Laufzeitüberprüfung ausgeführt wird. static_cast kann auf einer Verweisklasse Kompilierzeitüberprüfung übergeben aber weiterhin einen Fehler zur Laufzeit verursachen. In diesem Fall wird Platform::InvalidCastException ausgelöst. Im Allgemeinen müssen Sie diese Ausnahmen nicht behandeln, da sie fast immer Programmierfehler angeben, die Sie in der Regel während der Entwicklung und der Testphase beheben können.

Verwenden Sie static_cast , wenn der Code explizit eine Beziehung zwischen den beiden Typen deklariert. Daher können Sie sicher sein, dass die Umwandlung funktioniert.

    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

Der safe_cast-Operator ist Teil Windows-Runtime. Er führt eine Laufzeittypüberprüfung aus und löst Platform::InvalidCastException aus, wenn die Konvertierung fehlschlägt. Verwenden Sie safe_cast , wenn ein Laufzeitfehler eine außergewöhnliche Bedingung angibt. Der Hauptzweck von safe_cast ist die Identifizierung von Programmierfehlern während der Entwicklungs- und Testphasen an dem Punkt, an dem sie auftreten. Sie müssen die Ausnahme nicht behandeln, da der Ausnahmefehler selbst den Fehlerpunkt identifiziert.

Verwenden Sie safe_cast, wenn der Code nicht die Beziehung deklariert, aber Sie sicher sind, dass die Umwandlung funktioniert.

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

Wenn dynamic_cast Sie ein Objekt (genauer gesagt ein Hut ^) in einen abgeleiteten Typ umwandeln, erwarten Sie entweder, dass das Zielobjekt manchmal fehlschlägt nullptr oder dass die Umwandlung fehlschlägt, und Sie möchten diese Bedingung als regulären Codepfad anstelle einer Ausnahme behandeln. In der Projektvorlage "Leere App" (Universelle Windows-App) wird dynamic_cast die OnLaunched Methode in "app.xaml.cpp" verwendet, um zu testen, ob das App-Fenster Inhalte enthält. Es ist kein Fehler, wenn er keinen Inhalt hat. es ist eine erwartete Bedingung. Windows::Current::Content ist ein Windows::UI::XAML::UIElement und die Konvertierung erfolgt in einen Windows::UI.XAML::Controls::Frame, der ein besser abgeleiteter Typ in der Vererbungshierarchie ist.

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

Eine andere Verwendung von dynamic_cast ist die Überprüfung von einem Object^ , um zu bestimmen, ob es einen geschachtelten Werttyp enthält. In diesem Fall versuchen Sie dynamic_cast<Platform::Box> oder dynamic_cast<Platform::IBox>.

dynamic_cast und Nachverfolgungsverweise (%)

Sie können auch einen dynamic_cast Nachverfolgungsverweis anwenden, in diesem Fall verhält sich die Umwandlung jedoch wie safe_cast. Sie löst bei einem Fehler eine Platform::InvalidCastException aus, da ein Nachverfolgungsverweis keinen Wert von nullptraufweisen kann.

reinterpret_cast

Es wird empfohlen, nicht reinterpret_cast zu verwenden, da weder eine Kompilierzeitüberprüfung noch eine Laufzeitüberprüfung ausgeführt wird. Im schlimmsten Fall ist es möglich, reinterpret_cast dass Programmierfehler zur Entwicklungszeit nicht erkannt werden und subtile oder katastrophale Fehler im Verhalten Ihres Programms verursachen. Daher empfehlen wir, reinterpret_cast nur in den seltenen Fällen zu verwenden, wenn Sie eine Umwandlung zwischen nicht verknüpften Typen vornehmen müssen und Sie wissen, dass die Umwandlung erfolgt. Ein Beispiel für eine seltene Verwendung besteht darin, einen Windows-Runtime Typ in seinen zugrunde liegenden ABI-Typ zu konvertieren. Dies bedeutet, dass Sie die Steuerung der Verweiszählung für das Objekt übernehmen. Hierzu wird empfohlen, den intelligenten ComPtr Class -Zeiger verwenden. Andernfalls müssen Sie Release auf der Schnittstelle ausdrücklich aufrufen. Das folgende Beispiel veranschaulicht, wie eine Verweisklasse zu IInspectable*umgewandelt werden kann.

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

Wenn Sie zum Konvertieren von einer Windows-Runtime Schnittstelle in eine andere verwendenreinterpret_cast, wird das Objekt zweimal freigegeben. Verwenden Sie diese Umwandlung daher nur, wenn Sie in eine Nicht-C++-Komponentenerweiterungsschnittstelle konvertieren.

ABI-Typen

  • ABI-Typen befinden sich im Windows SDK in Headern. Praktischerweise sind die Header nach Namespaces benannt – z. B. windows.storage.h.

  • ABI-Typen befinden sich in einer speziellen Namespace-ABI – z. B. ABI::Windows::Storage::Streams::IBuffer*.

  • Konvertierungen zwischen einem Windows-Runtime Schnittstellentyp und seinem entsprechenden ABI-Typ sind immer sicher – dIBuffer^. h. in ABI::IBuffer*.

  • Wenn dies bekannt ist, sollte eine Windows-Runtime Klasse immer in IInspectable* die Standardschnittstelle oder die Standardschnittstelle konvertiert werden.

  • Nachdem Sie die Konvertierung in ABI-Typen durchgeführt haben, verfügen Sie über die Lebensdauer des Typs und müssen den COM-Regeln folgen. Wir empfehlen zum Vereinfachen der Lebensdauerverwaltung von ABI-Zeigern, WRL::ComPtr zu verwenden.

In der folgenden Tabelle werden die Fälle aufgeführt, in denen es sicher ist, reinterpret_castzu verwenden. In jedem Fall ist die Umwandlung in beide Richtungen sicher.

Cast from, cast to Cast in, cast from
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^*

Siehe auch