インターフェイス (C++/CX)

ref クラスは多くても 1 つの具象基底クラスからしか継承できませんが、任意の数のインターフェイス クラスを実装できます。 インターフェイス クラス (インターフェイス構造体) 自体は、複数のインターフェイス クラスを継承 (または要求) でき、メンバー関数をオーバーロードすることができ、型パラメーターを持つことができます。

特性

インターフェイスには、以下の特性があります。

  • インターフェイス クラス (または構造体) は、名前空間内部で宣言される必要があり、その名前空間内で public または private のアクセシビリティを持つことができます。 パブリック インターフェイスだけがメタデータに出力されます。

  • インターフェイスのメンバーには、プロパティ、メソッド、およびイベントを含めることができます。

  • すべてのインターフェイス メンバーは、暗黙的にパブリックであり、仮想です。

  • フィールドおよび静的メンバーは使用できません。

  • プロパティ、メソッド パラメーター、または戻り値として使用される型は Windows ランタイム型のみです。これには、基本型と enum クラス型が含まれています。

宣言と使用法

インターフェイスの宣言方法を次に示します。 インターフェイスはクラス型または構造体型として宣言できます。

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);
    };
}

インターフェイスを実装するには、ref クラスまたは ref 構造体で仮想メソッドと仮想プロパティを宣言し、実装します。 インターフェイスおよび ref クラスの実装では、この例に示すように、同じメソッド パラメーター名を使用する必要があります。

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:
    //...
};

インターフェイス継承階層

インターフェイスは、1 つ以上のインターフェイスから継承できます。 ただし、ref クラスまたは ref 構造体とは異なり、インターフェイスは継承インターフェイス メンバーを宣言しません。 インターフェイス B がインターフェイス A から継承し、ref クラス C が B から継承する場合、C は A と B の両方を実装する必要があります。これを次の例に示します。

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(){}
};


インターフェイスのプロパティとイベントの実装

前の例に示したように、単純な仮想プロパティを使用してインターフェイスのプロパティを実装できます。 また、実装するクラスでカスタムの get アクセス操作子および set アクセス操作子を提供できます。 インターフェイス プロパティで、get および set アクセス操作子が両方ともパブリックである必要があります。

//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; }
}

インターフェイスで取得専用または設定専用のプロパティを宣言する場合、実装するクラスは明示的に get または set アクセス操作子を提供する必要があります。

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;
};

また、実装するクラスでイベントのカスタムの追加および削除メソッドを実装できます。

明示的なインターフェイスの実装

ref クラスが複数のインターフェイスを実装し、それらのインターフェイスに名前と署名がコンパイラと同じメソッドがある場合、次の構文を使用して、クラス メソッドが実装しているインターフェイス メソッドを明示的に示すことができます。

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";}
};

ジェネリック インターフェイス

C++/CX では、Windows ランタイムのパラメーター化された型を表すために、generic キーワードが使用されます。 パラメーター化された型は、メタデータに出力され、型パラメーターをサポートする言語で記述されたコードで利用できます。 Windows ランタイムは、一部のジェネリック インターフェイス (Windows::Foundation::Collections::IVector<T> など) を定義しますが、C++/CX でのパブリック ユーザー定義ジェネリック インターフェイスの作成はサポートしません。 ただし、プライベート ジェネリック インターフェイスは作成できます。

ここで、Windows ランタイム型を使用してジェネリック インターフェイスを作成する方法を示します。

  • コンポーネント内のジェネリック ユーザー定義 interface class を Windows メタデータ ファイルに出力することはできません。したがって、パブリック アクセシビリティを持つことはできず、他の .winmd ファイル内のクライアント コードでは実装できません。 実装するには、同じコンポーネント内の非パブリック ref クラスを使用することが必要です。 パブリック ref クラスは、プライベート メンバーとしてジェネリック インターフェイス型を持つことができます。

    次のコード スニペットは、ジェネリック interface class を宣言してから、プライベート ref クラスに実装し、その ref クラスをパブリック ref クラスのプライベート メンバーとして使用する方法を示します。

    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;
    
    };
    
  • ジェネリック インターフェイスは、アクセシビリティ、メンバー、 要求 リレーションシップ、基底クラスなどを管理する標準インターフェイス規則に従う必要があります。

  • ジェネリック インターフェイスは、 typename または classを指定する 1 つ以上のジェネリック型パラメーターを受け取ることができます。 非型パラメーターはサポートされていません。

  • 型パラメーターには任意の Windows ランタイム型を使用できます。 つまり、型パラメーターには、参照型、値の型、インターフェイス クラス、デリゲート、基本型、またはパブリック列挙型クラスを指定できます。

  • クローズ ジェネリック インターフェイス は、ジェネリック インターフェイスから継承し、すべての型パラメーターに対して具象型引数を指定するインターフェイスです。 これは、非ジェネリック プライベート インターフェイスを使用できる場所のどこにでも使用できます。

  • オープン ジェネリック インターフェイス は、具象型がまだ提供されていない 1 つ以上の型パラメーターを持つインターフェイスです。 これは型を使用できる場所のどこにでも使用できます。これには、別のジェネリック インターフェイスの型引数としての使用も含まれます。

  • パラメーター化できるのは、個々のメソッドではなくインターフェイス全体だけです。

  • 型パラメーターを制約することはできません。

  • クローズ ジェネリック インターフェイスには、暗黙的に生成される UUID があります。 ユーザーは UUID を指定できません。

  • インターフェイスでは、メソッド パラメーター、戻り値、またはプロパティでの現在のインターフェイスへの参照は、現在のインスタンス化への参照と見なされます。 たとえば、IMyIntfIMyIntf<T> を意味します。

  • メソッド パラメーターの型が型パラメーターの場合、そのパラメーターまたは変数の宣言では、ポインター、ネイティブ参照、またはハンドル宣言子なしで型パラメーターの名前が使用されます。 つまり、"T^" を作成することはありません。

  • template 宣言された ref クラスは、プライベートである必要があります。 それらは、ジェネリック インターフェイスを実装でき、テンプレート パラメーター T を汎用引数 T に渡すことができます。テンプレート化された ref クラスの各インスタンス化は、それ自体が ref クラスです。

関連項目

型システム
C++/CX 言語リファレンス
名前空間参照