Muokkaa

Jaa


Casting (C++/CX)

Four different cast operators apply to Windows Runtime types: static_cast Operator, dynamic_cast Operator, safe_cast Operator, and reinterpret_cast Operator. safe_cast and static_cast throw an exception when the conversion can't be performed; static_cast Operator also performs compile-time type checking. dynamic_cast returns nullptr if it fails to convert the type. Although reinterpret_cast returns a non-null value, it might be invalid. For this reason, we recommend that you not use reinterpret_cast unless you know that the cast will succeed. In addition, we recommend that you not use C-style casts in your C++/CX code because they are identical to reinterpret_cast.

The compiler and runtime also perform implicit casts—for example, in boxing operations when a value type or built-in type are passed as arguments to a method whose parameter type is Object^. In theory, an implicit cast should never cause an exception at run time; if the compiler can't perform an implicit conversion, it raises an error at compile time.

Windows Runtime is an abstraction over COM, which uses HRESULT error codes instead of exceptions. In general, the Platform::InvalidCastException indicates a low-level COM error of E_NOINTERFACE.

static_cast

A static_cast is checked at compile time to determine whether there is an inheritance relationship between the two types. The cast causes a compiler error if the types are not related.

A static_cast on a ref class also causes a run-time check to be performed. A static_cast on a ref class can pass compile time verification but still fail at run time; in this case a Platform::InvalidCastException is thrown. In general, you don't have to handle these exceptions because almost always they indicate programming errors that you can eliminate during development and testing.

Use static_cast if the code explicitly declares a relationship between the two types, and you therefore are sure that the cast should work.

    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

The safe_cast operator is part of Windows Runtime. It performs a run-time type check and throws a Platform::InvalidCastException if the conversion fails. Use safe_cast when a run-time failure indicates an exceptional condition. The primary purpose of safe_cast is to help identify programming errors during the development and testing phases at the point where they occur. You don't have to handle the exception because the unhandled exception itself identifies the point of failure.

Use safe_cast if the code does not declare the relationship but you are sure that the cast should work.

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

Use dynamic_cast when you cast an object (more specifically, a hat ^) to a more derived type, you expect either that the target object might sometimes be nullptr or that the cast might fail, and you want to handle that condition as a regular code path instead of an exception. For example, in the Blank App (Universal Windows) project template, the OnLaunched method in app.xaml.cpp uses dynamic_cast to test whether the app window has content. It's not an error if it doesn't have content; it is an expected condition. Windows::Current::Content is a Windows::UI::XAML::UIElement and the conversion is to a Windows::UI.XAML::Controls::Frame, which is a more derived type in the inheritance hierarchy.

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

Another use of dynamic_cast is to probe an Object^ to determine whether it contains a boxed value type. In this case, you attempt a dynamic_cast<Platform::Box> or a dynamic_cast<Platform::IBox>.

dynamic_cast and tracking references (%)

You can also apply a dynamic_cast to a tracking reference, but in this case the cast behaves like safe_cast. It throws Platform::InvalidCastException on failure because a tracking reference cannot have a value of nullptr.

reinterpret_cast

We recommend that you not use reinterpret_cast because neither a compile-time check nor a run-time check is performed. In the worst case, a reinterpret_cast makes it possible for programming errors to go undetected at development time and cause subtle or catastrophic errors in your program's behavior. Therefore, we recommend that you use reinterpret_cast only in those rare cases when you must cast between unrelated types and you know that the cast will succeed. An example of a rare use is to convert a Windows Runtime type to its underlying ABI type—this means that you are taking control of the reference counting for the object. To do this, we recommend that you use the ComPtr Class smart pointer. Otherwise, you must specifically call Release on the interface. The following example shows how a ref class can be cast to an IInspectable*.

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

If you use reinterpret_cast to convert from one Windows Runtime interface to another, you cause the object to be released twice. Therefore, only use this cast when you are converting to a non-C++ component extensions interface.

ABI types

  • ABI types live in headers in the Windows SDK. Conveniently, the headers are named after the namespaces—for example, windows.storage.h.

  • ABI types live in a special namespace ABI—for example, ABI::Windows::Storage::Streams::IBuffer*.

  • Conversions between a Windows Runtime interface type and its equivalent ABI type are always safe—that is, IBuffer^ to ABI::IBuffer*.

  • A Windows Runtime class should always be converted to IInspectable* or its default interface, if that is known.

  • After you convert to ABI types, you own the lifetime of the type and must follow the COM rules. We recommend that you use WRL::ComPtr to simplify lifetime management of ABI pointers.

The following table summarizes the cases in which it is safe to use reinterpret_cast. In every case, the cast is safe in both directions.

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

See also