Compartilhar via


Interfaces (C++/CX)

Embora uma classe ref possa ser herdada de, no máximo, uma classe base concreta, ela pode implementar qualquer número de classes de interface. Uma classe de interface (ou estrutura de interface) em si pode herdar (ou exigir) várias classes de interface, pode sobrecarregar suas funções de membro e pode ter parâmetros de tipo.

Characteristics

Uma interface tem as seguintes características:

  • Uma classe (ou estrutura) de interface deve ser declarada dentro de um namespace e pode ter acessibilidade pública ou privada. Somente as interfaces públicas são emitidas para metadados.

  • Os membros da interface podem incluir propriedades, métodos e eventos.

  • Todos os membros de interface são implicitamente públicos e virtuais.

  • Campos e membros estáticos não são permitidos.

  • O tipos que são usados como propriedades, parâmetros de método ou valores de retorno somente podem ser tipos de Windows Runtime; isso inclui os tipos fundamentais e os tipos de classe enum.

Declaração e uso

O exemplo de código a seguir mostra como declarar uma interface. Observe que uma interface pode ser declarada como uma classe ou tipo de estrutura.

namespace InterfacesTest
{
    public enum class PlayState {Playing, Paused, Stopped, Forward, Reverse};

    public ref struct MediaPlayerEventArgs sealed
    {
        property PlayState oldState;
        property PlayState newState;
    };

    public delegate void OnStateChanged(Platform::Object^ sender, MediaPlayerEventArgs^ a);
    public interface class IMediaPlayer // or public interface struct IMediaPlayer 
    {
        event OnStateChanged^ StateChanged;
        property Platform::String^ CurrentTitle;
        property PlayState CurrentState;
        void Play();
        void Pause();
        void Stop();
        void Back(float speed);
        void Forward(float speed);
    };
}

Para implementar uma interface, uma classe ref ou estrutura ref declara e implementa métodos e propriedades virtuais. A interface e a classe ref de implementação devem usar os mesmos nomes de parâmetros de método, conforme mostrado neste exemplo:

public ref class MyMediaPlayer sealed : public IMediaPlayer
{
public:
    //IMediaPlayer
    virtual event OnStateChanged^ StateChanged;
    virtual property Platform::String^ CurrentTitle;
    virtual property PlayState CurrentState;
    virtual void Play()
    {
        // ...
        auto args = ref new MediaPlayerEventArgs(); 
        args->newState = PlayState::Playing;
        args->oldState = PlayState::Stopped;
        StateChanged(this, args);
    }
    virtual void Pause(){/*...*/}
    virtual void Stop(){/*...*/}
    virtual void Forward(float speed){/*...*/}
    virtual void Back(float speed){/*...*/}
private:
    //...
};

Hierarquias de herança de interface

Uma interface pode herdar de uma ou mais interfaces. Porém, diferentemente de uma classe ou estrutura ref, uma interface não declara os membros da interface herdada. Se a interface B for herdada da interface A, e a classe ref C for herdada de B, a C deverá implementar A e B. Isso é mostrado no exemplo a seguir.

public interface struct A { void DoSomething(); };
public interface struct B : A { void DoSomethingMore();};

public ref struct C sealed : B
{
    virtual void DoSomething(){}
    virtual void DoSomethingMore(){}
};


Implementando propriedades e eventos da interface

Conforme mostrado no exemplo anterior, você pode usar propriedades virtuais triviais para implementar propriedades de interface. Você também pode fornecer getters e setters personalizados na classe de implementação. Tanto getter quanto setter devem ser públicos em uma propriedade de interface.

//Alternate implementation in MediaPlayer class of IMediaPlayer::CurrentTitle
virtual property Platform::String^ CurrentTitle
{
    Platform::String^ get() {return "Now playing: " + _title;}
    void set(Platform::String^ t) {_title = t; }
}

Se uma interface declarar uma propriedade get-only ou set-only, a classe de implementação deverá fornecer explicitamente um getter ou setter.

public interface class IMediaPlayer
{
    //...
    property Platform::String^ CurrentTitle
    {
        Platform::String^ get();           
    }
};

public ref class MyMediaPlayer3 sealed : public IMediaPlayer
{
public:
    //...
    virtual property Platform::String^ CurrentTitle
    {
        Platform::String^ get() {return "Now playing: " + _title;}
    }
private:
    Platform::String^ _title;
};

Você também pode implementar métodos add e remove personalizados para eventos na classe de implementação.

Implementação de interface explícita

Quando uma classe ref implementa várias interfaces e estas têm métodos cujos nomes e assinaturas são idênticos para o compilador, você poderá usar a sintaxe a seguir para indicar explicitamente o método de interface que um método de classe está implementando.

public interface class IArtist
{     
    Platform::String^ Draw();
};

public interface class ICowboy
{
    Platform::String^ Draw();
};

public ref class MyClass sealed : public IArtist, ICowboy
{
public:     
    MyClass(){}     
    virtual  Platform::String^ ArtistDraw() = IArtist::Draw {return L"Artist";}
    virtual  Platform::String^ CowboyDraw() = ICowboy::Draw {return L"Cowboy";}
};

Interfaces genéricas

No C++/CX, a palavra-chave generic é usada para representar um tipo parametrizado do Windows Runtime. Um tipo parametrizado é emitido nos metadados e pode ser consumido pelo código que está escrito em qualquer linguagem que ofereça suporte aos parâmetros de tipo. O Windows Runtime define algumas interfaces genéricas, por exemplo, Windows::Foundation::Collections::IVector<T>, mas não oferece suporte à criação de interfaces genéricas públicas definidas pelo usuário em C++/CX. No entanto, é possível criar interfaces genéricas privadas.

Veja como os tipos do Windows Runtime podem ser usados para criar uma interface genérica:

  • Uma interface class genérica definida pelo usuário em um componente não tem permissão para ser emitida no seu arquivo de metadados do Windows; portanto, ela não pode ter acessibilidade pública e o código do cliente em outros arquivos .winmd não pode implementá-lo. Ela pode ser implementada por classes ref não públicas no mesmo componente. Uma classe ref pública pode ter um tipo de interface genérica como um membro privado.

    O snippet de código a seguir mostra como declarar uma interface class genérica e implementá-la em uma classe ref privada, bem como a usar a classe ref como um membro privado em uma classe ref pública.

    public ref class MediaFile sealed {};
    
    generic <typename T>
    private interface class  IFileCollection
    {
        property Windows::Foundation::Collections::IVector<T>^ Files;
        Platform::String^  GetFileInfoAsString(T file);
    };
    
    private ref class MediaFileCollection : IFileCollection<MediaFile^>
    {
    public:
        virtual property Windows::Foundation::Collections::IVector<MediaFile^>^ Files;
        virtual Platform::String^  GetFileInfoAsString(MediaFile^ file){return "";}
    };
    
    public interface class ILibraryClient
    {
        bool FindTitle(Platform::String^ title);       
        //...
    };
    
    public ref class MediaPlayer sealed : public IMediaPlayer, public ILibraryClient
    {
    public:
        //IMediaPlayer
        virtual event OnStateChanged^ StateChanged;
        virtual property Platform::String^ CurrentTitle;
        virtual property PlayState CurrentState;
        virtual void Play()
        {
            auto args = ref new MediaPlayerEventArgs(); 
            args->newState = PlayState::Playing;
            args->oldState = PlayState::Stopped;
            StateChanged(this, args);
        }
        virtual void Pause(){/*...*/}
        virtual void Stop(){/*...*/}
        virtual void Forward(float speed){/*...*/}
        virtual void Back(float speed){/*...*/}
    
        //ILibraryClient
        virtual bool FindTitle(Platform::String^ title){/*...*/ return true;}
    
    private:
        MediaFileCollection^ fileCollection;
    
    };
    
  • Uma interface genérica deve seguir as regras de interface padrão que controlam a acessibilidade, os membros, as relações requires , as classes base, etc.

  • Uma interface genérica pode usar um ou mais parâmetros de tipos genéricos que são precedidos por typename ou class. Não há suporte para parâmetros sem tipo.

  • Um parâmetro de tipo pode ser qualquer tipo do Windows Runtime. Ou seja, o parâmetro de tipo pode ser um tipo de referência, um tipo de valor, uma classe de interface, um representante, um tipo fundamental ou uma classe enum pública.

  • Uma interface genérica fechada é uma interface que herda de uma interface genérica e especifica argumentos de tipo concreto para todos os parâmetros de tipo. Ela pode ser usada em qualquer lugar em que uma interface privada não genérica possa ser usada.

  • Uma interface genérica aberta é uma interface que tem um ou mais parâmetros de tipo para os quais nenhum tipo concreto é fornecido. Ela pode ser usada em qualquer lugar em que um tipo possa ser usado; incluindo como um argumento de tipo de outra interface genérica.

  • Você pode parametrizar apenas uma interface inteira, não métodos individuais.

  • Parâmetros de tipo não podem ser restritos.

  • Uma interface genérica fechada tem um UUID gerado implicitamente. Um usuário não pode especificar o UUID.

  • Na interface, qualquer referência à interface atual, em um parâmetro de método, valor de retorno ou propriedade, é assumido como referência à instanciação atual. Por exemplo, IMyIntf significa IMyIntf<T>.

  • Quando o tipo de um parâmetro de método é um parâmetro de tipo, a declaração desse parâmetro ou variável usa o nome do parâmetro de tipo sem nenhum ponteiro, referência nativa ou declaradores de identificador. Em outras palavras, você nunca escreve "T^".

  • As classes ref no modelo devem ser privadas. Eles podem implementar interfaces genéricas e podem passar o parâmetro de modelo T para o argumento genérico T. Cada instanciação de uma classe ref modelada é em si uma classe ref.

Confira também

Sistema de tipos
Referência da linguagem C++/CX
Referência de namespaces