Conversão (C++/CX)
Quatro operadores cast diferentes se aplicam a tipos do Windows Runtime : Operador static_cast, Operador dynamic_cast, Operador safe_caste Operador reinterpret_cast. safe_cast e static_cast
geram uma exceção quando a conversão não pode ser executada; o Operador static_cast também executa a verificação de tipo em tempo de compilação. dynamic_cast
retornará nullptr
se não converter o tipo. Embora reinterpret_cast
retorne um valor não nulo, ele poderá ser inválido. Por esse motivo, é recomendável não usar reinterpret_cast
a menos que você saiba que a conversão funcionará. Além disso, recomendamos que você não use conversões no estilo C em seu código C++/CX porque elas são idênticas a reinterpret_cast
.
O compilador e o runtime também executam conversões implícitas - por exemplo, em operações de conversão boxing quando um tipo de valor ou um tipo interno é transmitido como argumentos para um método cujo tipo de parâmetro é Object^
. Em tese, uma conversão implícita nunca deve causar uma exceção no tempo de execução; se o compilador não puder executar uma conversão implícita, ele gerará um erro no tempo de compilação.
O Windows Runtime é uma abstração sobre COM, que usa os códigos de erro HRESULT em vez de exceções. Em geral, Platform::InvalidCastException indica um erro COM de nível baixo de E_NOINTERFACE.
static_cast
Um static_cast
é verificado no tempo de compilação para determinar se há uma relação de herança entre os dois tipos. A conversão causará um erro do compilador se os tipos não estiverem relacionados.
Um static_cast
em uma classe ref também faz com que uma verificação de tempo de execução seja executada. static_cast
em uma classe de referência pode transmitir a verificação de tempo de compilação, mas ainda falhar no tempo de execução; Platform::InvalidCastException
é lançada nesse caso. Geralmente, você não precisa tratar essas exceções, pois quase sempre elas indicam erros de programação que você pode eliminar durante as fases de desenvolvimento e teste.
Use static_cast
se o código declarar explicitamente uma relação entre os dois tipos e se você estiver certo de que a conversão funcionará.
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
O operador safe_cast faz parte do Windows Runtime. Ele executa uma verificação de tipo no tempo de execução e gera Platform::InvalidCastException
se houver falhas na conversão. Use safe-cast quando uma falha no tempo de execução indicar uma condição excepcional. O objetivo principal de safe_cast é ajudar a identificar erros de programação durante as fases de desenvolvimento e teste no ponto em que eles ocorrem. Você não precisa lidar com a exceção porque a própria exceção não tratada identifica o ponto de falha.
Use safe_cast se o código não declarar a relação e você tiver certeza de que a conversão funcionará.
// 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
quando converter um objeto (mais especificamente, ^) em um tipo mais derivado, e esperar que o objeto de destino seja ocasionalmente nullptr
ou que a conversão falhe, e você desejar tratar essa condição como um caminho do código regular, em vez de uma exceção. Por exemplo, no modelo de projeto Aplicativo em Branco (Windows Universal), o método OnLaunched
em app.xaml usa dynamic_cast
para testar se a janela do aplicativo tem conteúdo. Não é um erro se não tiver conteúdo; é uma condição esperada. Windows::Current::Content
é um Windows::UI::XAML::UIElement
, e a conversão é em Windows::UI.XAML::Controls::Frame
, que é um tipo mais derivado na hierarquia de herança.
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();
// ...
}
}
Outro uso de dynamic_cast
é investigar um Object^
para determinar se ele contém um tipo de valor demarcado. Nesse caso, você tenta um dynamic_cast<Platform::Box>
ou um dynamic_cast<Platform::IBox>
.
dynamic_cast e referências de acompanhamento (%)
Você também pode aplicar dynamic_cast
a uma referência de acompanhamento, mas nesse caso a conversão se comporta como safe_cast. Ela gera Platform::InvalidCastException
em caso de falha porque uma referência de acompanhamento não pode ter um valor de nullptr
.
reinterpret_cast
É recomendável não usar reinterpret_cast , pois não serão executadas verificações de tempo de compilação nem de tempo de execução. Na pior das hipóteses, a reinterpret_cast
possibilita que erros de programação não sejam detectados no tempo de desenvolvimento e causem erros sutis ou catastróficos no comportamento do seu programa. Dessa forma, recomendamos que você use reinterpret_cast
apenas em casos raros em que for necessário converter tipos não relacionados e você tiver certeza de que a conversão funcionará. Um exemplo de uso incomum é converter um tipo do Windows Runtime ao seu tipo de ABI subjacente. Isso significa que você está assumindo o controle da contagem de referência para o objeto. Para fazer isso, recomendamos usar o ponteiro inteligente ComPtr Class . Caso contrário, você deverá chamar especificamente a versão na interface. O exemplo a seguir mostra como uma classe de referência pode ser convertida em IInspectable*
.
#include <wrl.h>
using namespace Microsoft::WRL;
auto winRtObject = ref new SomeWinRTType();
ComPtr<IInspectable> inspectable = reinterpret_cast<IInspectable*>(winRtObject);
// ...
Se você usar reinterpret_cast
para converter uma interface do Windows Runtime em outra, o objeto será liberado duas vezes. Portanto, somente use essa conversão quando estiver convertendo em uma interface de extensões de componente não C++.
Tipos de ABI.
Os tipos de ABI permanecem ativos em cabeçalhos no Windows SDK. Convenientemente, os cabeçalhos são nomeados com namespaces - por exemplo,
windows.storage.h
.Os tipos de ABI permanecem ativos em uma ABI de namespace especial - por exemplo,
ABI::Windows::Storage::Streams::IBuffer*
.Conversões entre um tipo de interface do Windows Runtime e seu tipo de ABI equivalente são sempre seguras, ou seja,
IBuffer^
aABI::IBuffer*
.Uma classe do Tempo de Execução do Windows sempre deve ser convertida em
IInspectable*
ou sua interface padrão, se isso for conhecido.Depois de converter em tipos de ABI, você possui o tempo de vida do tipo e deverá seguir as regras COM. Recomendamos usar
WRL::ComPtr
para simplificar o gerenciamento de tempo de vida de ponteiros de ABI.
A tabela a seguir resume os casos em que é seguro usar reinterpret_cast
. Em todos os casos, a conversão é segura em ambas as direções.
Converter de, converter em | Converter em, converter de |
---|---|
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^* |