Поделиться через


Приведение (C++/CX)

Четыре разных оператора приведения применяются к типам среда выполнения Windows: оператор static_cast, оператор dynamic_cast, оператор safe_cast и оператор reinterpret_cast. safe_cast и static_cast возникает исключение, если преобразование не может быть выполнено; оператор static_cast также выполняет проверку типа во время компиляции. dynamic_cast возвращает значение nullptr , если не удается преобразовать тип. Хотя reinterpret_cast возвращает значение, отличное от NULL, оно может быть неверным. По этой причине рекомендуется не использовать reinterpret_cast , если нет уверенности, что приведение завершится успешно. Кроме того, рекомендуется не использовать приведения стилей C в коде C++/CX, так как они идентичны reinterpret_cast.

Компилятор и среда выполнения также выполняют неявное приведение, например в операциях упаковки, когда тип значения или встроенный тип передаются как аргументы в метод, параметры которого имеют тип Object^. Теоретически неявное приведение никогда не должно вызвать исключение во время выполнения; если компилятор не может выполнить неявное преобразование, он вызывает ошибку во время компиляции.

среда выполнения Windows — это абстракция по com, которая использует коды ошибок HRESULT вместо исключений. Как правило, Platform::InvalidCastException указывает на низкоуровневую ошибку E_NOINTERFACE модели COM.

static_cast

static_cast проверяется во время компиляции, чтобы определить, есть ли отношения наследования между двумя типами. Приведение вызывает ошибку компилятора, если типы не связаны.

Применение static_cast к классу ссылки также вызывает проверку времени выполнения. Применение static_cast к классам ссылок может пройти проверку при компиляции, но все равно приведет к сбою во время выполнения; в этом случае создается исключение Platform::InvalidCastException . В общем случае не следует обрабатывать эти исключения, поскольку они почти всегда указывают на ошибки программирования, которые можно устранить на этапах разработки и тестирования.

Используйте 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 используется dynamic_cast для проверки наличия содержимого окна приложения.OnLaunched Это не ошибка, если она не имеет содержимого; это ожидаемое условие. Windows::Current::Content является Windows::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 — проверка объекта 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 рекомендуется только в тех редких случаях, когда необходимо выполнять приведение между несвязанными типами и известно, что такое приведение будет выполнено успешно. Примером редкого использования является преобразование типа среда выполнения Windows в базовый тип ABI. Это означает, что вы управляете подсчетом ссылок для объекта. Для этого рекомендуется использовать интеллектуальный указатель ComPtr Class . В противном случае необходимо явно вызывать Release для интерфейса. В следующем примере показано, как класс ссылки может быть приведен к IInspectable*.

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

Если вы используете reinterpret_cast для преобразования из одного интерфейса среда выполнения Windows в другой, объект будет выпущен дважды. Поэтому используйте этот приведение только при преобразовании в интерфейс расширений компонентов, отличных от C++.

Типы ABI

  • Типы ABI расположены в заголовках в Windows SDK. Для удобства имена заголовков соответствуют именам пространств имен, например windows.storage.h.

  • Типы ABI расположены в специальном пространстве имен ABI, например ABI::Windows::Storage::Streams::IBuffer*.

  • Преобразования между типом интерфейса среда выполнения Windows и его эквивалентным типом ABI всегда безопасны , то есть IBuffer^ ABI::IBuffer*в .

  • Класс среда выполнения Windows всегда должен быть преобразован в IInspectable* или его интерфейс по умолчанию, если это известно.

  • После преобразования к типам ABI вы управляете временем жизни типа и должны соблюдать правила модели COM. Рекомендуется использовать WRL::ComPtr , чтобы упростить управление временем жизни указателей ABI.

В следующей таблице приведены случаи, в которых безопасно использовать 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^*

См. также