Partilhar via


Fundição (C++/CX)

Quatro operadores de transmissão diferentes se aplicam aos tipos do Tempo de Execução do Windows: Operador static_cast, Operador dynamic_cast, Operador safe_cast e Operador reinterpret_cast. safe_cast e static_cast lançam uma exceção quando a conversão não puder ser executada; o operador static_cast também executa a verificação de tipo em tempo de compilação. dynamic_cast retorna nullptr se não conseguir converter o tipo. Embora reinterpret_cast retorne um valor não nulo, ele pode ser inválido. Por esse motivo, recomendamos que você não use reinterpret_cast a menos que saiba que o elenco terá sucesso. Além disso, recomendamos que não utilize conversões de tipo estilo C no seu código C++/CX porque são idênticas a reinterpret_cast.

O compilador e o tempo de execução também realizam conversões implícitas — por exemplo, em operações de boxing quando um tipo de valor ou tipo embutido é passado como argumento para um método cujo tipo de parâmetro é Object^. Em teoria, um elenco implícito nunca deve causar uma exceção em tempo de execução; Se o compilador não pode executar uma conversão implícita, ele gera um erro em tempo de compilação.

O Tempo de Execução do Windows é uma abstração sobre COM, que usa códigos de erro HRESULT em vez de exceções. Em geral, o Platform::InvalidCastException indica um erro COM de baixo nível de E_NOINTERFACE.

static_cast

O static_cast é verificado durante a compilação para determinar se há uma relação de herança entre os dois tipos. O cast causa um erro de compilador se os tipos não estiverem relacionados.

A static_cast em uma classe ref também faz com que uma verificação de tempo de execução seja executada. Um static_cast numa classe de referência pode passar na verificação de tempo de compilação, mas ainda falhar em tempo de execução; neste caso, um Platform::InvalidCastException é lançado. Em geral, você não precisa lidar com essas exceções porque quase sempre elas indicam erros de programação que você pode eliminar durante o desenvolvimento e o teste.

Use static_cast se o código declarar explicitamente uma relação entre os dois tipos e, portanto, você tiver certeza de que o elenco deve 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 Tempo de Execução do Windows. Realiza uma verificação de tipo em tempo de execução e lança um Platform::InvalidCastException se a conversão falhar. Use safe_cast quando uma falha em tempo de execução indicar uma condição excecional. O principal objetivo do safe_cast é ajudar a identificar erros de programação durante as fases de desenvolvimento e teste no ponto em que ocorrem. Não é necessário manipular 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, mas tiveres a certeza de que a conversão deve 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 você converte um objeto (mais especificamente, um chapéu ^) para um tipo mais derivado, você espera que o objeto de destino às vezes possa ser nullptr ou que a conversão possa falhar, e você deseja manipular essa condição como um caminho de código regular em vez de uma exceção. Por exemplo, no modelo de projeto Aplicativo em Branco (Universal Windows), o OnLaunched método em app.xaml.cpp 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 é a Windows::UI::XAML::UIElement e a conversão é para um 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 contém um tipo de valor embutido. Nesse caso, tenta um dynamic_cast<Platform::Box> ou um dynamic_cast<Platform::IBox>.

dynamic_cast e referências de rastreamento (%)

Você também pode aplicar um dynamic_cast a uma referência de rastreamento, mas neste caso o elenco se comporta como safe_cast. Lança uma falha Platform::InvalidCastException porque uma referência de rastreamento não pode ter um valor de nullptr.

reinterpret_cast (operador de conversão de tipo em C++)

Recomendamos que você não use reinterpret_cast porque nem uma verificação em tempo de compilação nem uma verificação em tempo de execução são executadas. Na pior das hipóteses, a reinterpret_cast torna possível que erros de programação não sejam detetados no momento do desenvolvimento e causem erros sutis ou catastróficos no comportamento do seu programa. Portanto, recomendamos que você use reinterpret_cast apenas nos raros casos em que você deve lançar entre tipos não relacionados e você sabe que o elenco terá sucesso. Um exemplo de um uso raro é converter um tipo do Runtime do Windows no seu tipo ABI subjacente — isto significa que você está a tomar controlo da contagem de referências para o objeto. Para fazer isso, recomendamos que você use o ponteiro inteligente ComPtr Class . Caso contrário, você deve chamar especificamente Release na interface. O exemplo a seguir mostra como uma classe ref pode ser convertida para um 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 de uma interface do Tempo de Execução do Windows para outra, fará com que o objeto seja liberado duas vezes. Portanto, use este cast somente quando estiver a converter para uma interface de extensões de componentes que não são C++.

Tipos de ABI

  • Os tipos de ABI vivem em cabeçalhos no SDK do Windows. Convenientemente, os cabeçalhos são nomeados após os namespaces — por exemplo, windows.storage.h.

  • Os tipos ABI vivem num espaço de nomes especial ABI — por exemplo, ABI::Windows::Storage::Streams::IBuffer*.

  • As conversões entre um tipo de interface do Tempo de Execução do Windows e seu tipo ABI equivalente são sempre seguras, ou seja, IBuffer^ para ABI::IBuffer*.

  • Uma classe do Tempo de Execução do Windows deve sempre ser convertida em IInspectable* ou na sua interface padrão, caso essa seja conhecida.

  • Depois de converter para tipos ABI, você possui o tempo de vida do tipo e deve seguir as regras COM. Recomendamos que você use WRL::ComPtr para simplificar o gerenciamento do tempo de vida dos ponteiros ABI.

A tabela a seguir resume os casos em que é seguro usar reinterpret_cast. Em todos os casos, o elenco está seguro em ambas as direções.

Transmitir de, transmitir para Conversão para, conversão 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^*

Ver também