キャスト (C++/CX)

4 つの異なるキャスト演算子である static_cast Operatordynamic_cast Operatorsafe_cast Operator、および reinterpret_cast Operator が Windows ランタイム型に適用されます。 safe_caststatic_cast では、変換を実行できない場合に例外をスローします。static_cast 演算子では、コンパイル時の型チェックも実行します。 dynamic_cast は、型を変換できない場合 nullptr を返します。 reinterpret_cast は NULL 以外の値を返しますが、その値が無効な場合があります。 この理由で、キャストが成功することがわかっている場合を除き、 reinterpret_cast を使用しないことをお勧めします。 また、C スタイル キャストは reinterpret_cast と同じであるため、C++/CX コード内では使用しないことをお勧めします。

コンパイラとランタイムは、暗黙的なキャストも実行します。たとえば、ボックス化操作で、パラメーターの型が Object^であるメソッドに値型または組み込み型が引数として渡される場合です。 理論的には、暗黙的なキャストは実行時に例外を引き起こしません。コンパイラが暗黙的な変換を実行できない場合は、コンパイル時にエラーが発生します。

Windows ランタイムは COM を抽象化したものであり、例外の代わりに HRESULT エラー コードを使用します。 一般に、 Platform::InvalidCastException は E_NOINTERFACE の低レベルの COM エラーを表します。

static_cast

コンパイル時に static_cast をチェックすることで、2 つの型の間に継承関係が存在するかどうかを判断します。 2 つの型に継承関係がない場合は、キャストによってコンパイラ エラーが発生します。

ref クラスの static_cast は、ランタイムのチェックも実行します。 ref クラスに対する static_cast はコンパイル時の検証でエラーになりませんが、実行時にはエラーになります。この場合、 Platform::InvalidCastException がスローされます。 一般的に、このような例外を処理する必要はありません。ほとんどの例外は常に、開発時およびテスト時に解決できるプログラミング エラーを示しているためです。

2 つの型の間の関係をコードが明示的に宣言し、したがってキャストが機能することを確信している場合は、 static_cast を使用します。

    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

safe_cast 演算子は Windows ランタイムの一部です。 変換が失敗すると、実行時の型チェックを実行して Platform::InvalidCastException をスローします。 実行時エラーが例外条件を示している場合は safe_cast を使用します。 safe_cast の主な目的は、開発フェーズおよびテスト フェーズにおけるプログラミング エラーを発生時点で識別しやすくすることです。 ハンドルされていない例外自体がエラーの位置を示しているため、例外を処理する必要はありません。

コードが関係を宣言していないが、キャストが機能することを確信している場合は、safe_cast を使用します。

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

dynamic_cast を使用するのは、オブジェクト (具体的にはハット ^) をより強い派生型にキャストするときに、ターゲット オブジェクトが nullptr になる可能性があるか、キャストが失敗する可能性があり、その状況を例外ではなく通常のコード パスとして処理する必要がある場合です。 たとえば、空のアプリ (ユニバーサル Windows) プロジェクト テンプレートの場合、app.xaml.cpp の OnLaunched メソッドによって dynamic_cast を使用してアプリ ウィンドウにコンテンツが含まれているかどうかをテストします。 コンテンツがない場合はエラーではありません。これは予期される条件です。 Windows::Current::ContentWindows::UI::XAML::UIElement であり、継承階層内のより強い派生型である Windows::UI.XAML::Controls::Frameへの変換が実行されます。

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

dynamic_cast のもう 1 つの用途は、ボックス化された値型を持つかどうかを判断するために Object^ を調べることです。 この場合、 dynamic_cast<Platform::Box> または dynamic_cast<Platform::IBox>を試行します。

dynamic_cast と追跡参照 (%)

dynamic_cast を追跡参照に適用することもできますが、この場合キャストは safe_cast と同様に動作します。 追跡参照は Platform::InvalidCastException の値を持つことができないため、エラーが発生した場合は nullptrをスローします。

reinterpret_cast

reinterpret_cast を使用しないことをお勧めします。コンパイル時のチェックと、ランタイム チェックのどちらも実行されないためです。 最悪の場合、 reinterpret_cast プログラミング エラーが開発時に検出されず、プログラムの動作に微妙または致命的なエラーが発生する可能性があります。 したがって、関係のない型の間でキャストを実行する必要があり、そのキャストが正常に実行される確証があるという非常にまれな状況でのみ、 reinterpret_cast を使用することをお勧めします。 まれな使用例の 1 つは、Windows ランタイム型を基になる ABI の型に変換する場合です。この場合は、オブジェクトに対する参照カウントが管理されています。 この作業を行うには、 ComPtr Class のスマート ポインターを使用することをお勧めします。 それ以外の場合、特にインターフェイスに対して Release を呼び出す必要があります。 次の例では、ref クラスを IInspectable*にキャストする方法を示します。

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

reinterpret_cast を使用して Windows ランタイムのインターフェイスを別のインターフェイスに変換すると、オブジェクトを 2 回解放することになります。 したがって、C++ 以外のコンポーネント拡張インターフェイスに変換する場合にのみ、このキャストを使用します。

ABI の型

  • ABI の型は、Windows SDK のヘッダーに置かれます。 判別しやすいように、ヘッダーは名前空間にちなんだ名前が付けられています ( windows.storage.hなど)。

  • ABI の型は、 ABI::Windows::Storage::Streams::IBuffer*のような特殊な ABI 名前空間に置かれます。

  • Windows ランタイムのインターフェイス型と、それに対応する ABI の型との変換は常に安全です (たとえば IBuffer^ から ABI::IBuffer*)。

  • Windows ランタイム クラスが既知の場合は、常にその既定のインターフェイスにIInspectable*変換する必要があります。

  • ABI の型への変換後は、その型の有効期間を管理し、COM 規則に従う必要があります。 ABI のポインターの有効期間管理を容易にするために、 WRL::ComPtr を使用することをお勧めします。

次の表に、 reinterpret_castを使用しても安全な状況の概要を示します。 どの状況でも、キャストは両方向とも安全です。

キャスト元、キャスト先 キャスト先、キャスト元
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^*

関連項目