Приведение (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^* |