Interfejsy (C++/CX)
Mimo że klasa ref może dziedziczyć z co najwyżej jednej klasy bazowej, może implementować dowolną liczbę klas interfejsów. Sama klasa interfejsu (lub struktura interfejsu) może dziedziczyć (lub wymagać) wielu klas interfejsu, może przeciążać funkcje składowe i może mieć parametry typu.
Charakterystyki
Interfejs ma następujące cechy:
Klasa interfejsu (lub struktura) musi być zadeklarowana w przestrzeni nazw i może mieć dostęp publiczny lub prywatny. Tylko interfejsy publiczne są emitowane do metadanych.
Elementy członkowskie interfejsu mogą zawierać właściwości, metody i zdarzenia.
Wszystkie elementy członkowskie interfejsu są niejawnie publiczne i wirtualne.
Pola i statyczne elementy członkowskie są niedozwolone.
Typy, które są używane jako właściwości, parametry metody lub zwracane wartości mogą być tylko środowisko wykonawcze systemu Windows typów; obejmuje to typy podstawowe i typy klas wyliczenia.
Deklaracja i użycie
W poniższym przykładzie pokazano, jak zadeklarować interfejs. Zwróć uwagę, że interfejs można zadeklarować jako klasę lub typ struktury.
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);
};
}
Aby zaimplementować interfejs, klasa ref lub struktura ref deklaruje i implementuje metody wirtualne i właściwości. Interfejs i implementowanie klasy ref muszą używać tych samych nazw parametrów metody, jak pokazano w tym przykładzie:
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:
//...
};
Hierarchie dziedziczenia interfejsu
Interfejs może dziedziczyć z co najmniej jednego interfejsu. Jednak w przeciwieństwie do klasy ref lub struktury interfejs nie deklaruje odziedziczonych składowych interfejsu. Jeśli interfejs B dziedziczy z interfejsu A, a klasa ref C dziedziczy po B, C musi zaimplementować zarówno A, jak i B. Zostanie to pokazane w następnym przykładzie.
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(){}
};
Implementowanie właściwości i zdarzeń interfejsu
Jak pokazano w poprzednim przykładzie, można użyć trywialnych właściwości wirtualnych do zaimplementowania właściwości interfejsu. Można również udostępnić niestandardowe metody pobierania i ustawiacze w klasie implementowania. Zarówno getter, jak i setter muszą być publiczne we właściwości interfejsu.
//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; }
}
Jeśli interfejs deklaruje właściwość get-only lub set-only, klasa implementowania powinna jawnie podać metodę getter lub 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;
};
Można również zaimplementować niestandardowe metody dodawania i usuwania zdarzeń w klasie implementowania.
Implementacja jawnego interfejsu
Gdy klasa ref implementuje wiele interfejsów, a te interfejsy mają metody, których nazwy i podpisy są identyczne z kompilatorem, można użyć następującej składni, aby jawnie wskazać metodę interfejsu implementaną przez metodę klasy.
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";}
};
Interfejsy ogólne
W języku C++/CX generic
słowo kluczowe jest używane do reprezentowania typu środowisko wykonawcze systemu Windows sparametryzowanego. Typ sparametryzowany jest emitowany w metadanych i może być używany przez kod napisany w dowolnym języku, który obsługuje parametry typu. Środowisko wykonawcze systemu Windows definiuje niektóre interfejsy ogólne — na przykład Windows::Foundation::Collections::IVector<T> — ale nie obsługuje tworzenia publicznych interfejsów ogólnych zdefiniowanych przez użytkownika w języku C++/CX. Można jednak utworzyć prywatne interfejsy ogólne.
Poniżej przedstawiono sposób użycia typów środowisko wykonawcze systemu Windows do tworzenia interfejsu ogólnego:
Ogólny użytkownik zdefiniowany
interface class
w składniku nie może być emitowany do pliku metadanych systemu Windows. W związku z tym nie może mieć dostępu publicznego, a kod klienta w innych plikach winmd nie może go zaimplementować. Można ją zaimplementować za pomocą klas ref innych niż publiczne w tym samym składniku. Publiczna klasa ref może mieć ogólny typ interfejsu jako prywatny element członkowski.Poniższy fragment kodu pokazuje, jak zadeklarować rodzaj,
interface class
a następnie zaimplementować go w prywatnej klasie ref i użyć klasy ref jako prywatnej składowej w klasie publicznej 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; };
Interfejs ogólny musi być zgodny ze standardowymi regułami interfejsu, które zarządzają ułatwieniami dostępu, elementami członkowskimi, wymagają relacji, klas bazowych itd.
Interfejs ogólny może przyjmować co najmniej jeden ogólny parametr typu, który jest poprzedzony ciągiem
typename
lubclass
. Parametry inne niż typ nie są obsługiwane.Parametr typu może być dowolnym typem środowisko wykonawcze systemu Windows. Oznacza to, że parametr typu może być typem odwołania, typem wartości, klasą interfejsu, delegatem, typem podstawowym lub publiczną klasą wyliczenia.
Zamknięty interfejs ogólny to interfejs, który dziedziczy z interfejsu ogólnego i określa konkretne argumenty typu dla wszystkich parametrów typu. Można go używać w dowolnym miejscu, w przypadku którego można użyć nieogólnego interfejsu prywatnego.
Otwarty interfejs ogólny to interfejs, który ma co najmniej jeden parametr typu, dla którego nie podano jeszcze żadnego konkretnego typu. Można go używać w dowolnym miejscu, w których można używać typu, w tym jako argument typu innego interfejsu ogólnego.
Można sparametryzować tylko cały interfejs, a nie poszczególne metody.
Nie można ograniczyć parametrów typu.
Zamknięty interfejs ogólny ma niejawnie wygenerowany identyfikator UUID. Użytkownik nie może określić identyfikatora UUID.
W interfejsie zakłada się, że wszystkie odwołania do bieżącego interfejsu — w parametrze metody, zwracanej wartości lub właściwości — odwołują się do bieżącego wystąpienia. Na przykład IMyIntf oznacza IMyIntf<T>.
Gdy typ parametru metody jest parametrem typu, deklaracja tego parametru lub zmiennej używa nazwy parametru typu bez żadnego wskaźnika, odwołania natywnego lub deklaratorów obsługi. Innymi słowy, nigdy nie piszesz "T^".
Klasy ref szablonów muszą być prywatne. Mogą implementować interfejsy ogólne i mogą przekazać parametr szablonu T do argumentu ogólnego T. Każde wystąpienie klasy ref szablonu jest samą klasą ref.
Zobacz też
System typów
Dokumentacja języka C++/CX
Dokumentacja przestrzeni nazw