25.インターフェイス
interface はクラス実装することに同意する契約を定義します。
この契約は実装クラスが定義するべき仮想メンバ一式によって成り立ち、そして、その同意は
interface implementation(インターフェイス実装)と呼びます。
インターフェイスはまた他のインターフェイスを実装する実装クラスを要請することができます。
クラスは複数のインターフェイスを実装できます。
インターフェイスはそのインスタンス・メンバのいずれの定義も提供しません。
25.1 インターフェイス定義
インターフェイス・クラスは
class-key interface class ないし、 interface struct(
§19.1)によって定義されたクラスです。
interface class と interface struct 定義は等価です。インターフェイス中のメンバへのデフォルト・アクセス可能性は public で、このアクセス可能性は変更できません。
インターフェイス・クラス定義は
attributes(属性)(
§29)、
top-level-visibility(上層型識別)(
§12.4)、
そして、
base-clause(基底節)(
§21.1.1)のセットを含むことができます。
インターフェイス・クラス定義は
class-modifiers(クラス修飾子)を含むべきではありません。
インターフェイス・クラス定義はネイティブ・クラス定義中にネストすることができます。
しかしながら、ネイティブ・クラス定義はインターフェイス・クラス定義の中にネストされるべきではありません。
メタデータの詳細は
§34.12を参照のこと。
25.1.1 インターフェイス基底仕様
インターフェイス・クラス定義は
base-clause(基底節)指定を含むことができ、それらは定義されたインターフェイスの
explicit base interface(明示的な基底インターフェイス) として定義します。
インターフェイスの
base interface(基底インターフェイス)は明示的基底インターフェイスとその基底インターフェイスです。
それは、基底インターフェイスのセットは明示的基底インターフェイス、その明示的基底インターフェイス、等々、の完全他動クロージャであるのです。
インターフェイスはその基底インターフェイスの全てのメンバを継承します。
インターフェイスを実装した型もまた暗黙のうちにそのインターフェイスの基底インターフェイスの全てを実装します。
25.2 インターフェイス・メンバ
インターフェイスのメンバはその基底インターフェイスから継承されたメンバと、インターフェイス自身によって宣言されたメンバです。
インターフェイス定義は 0 以上のメンバによって宣言できます。
インターフェイスのメンバは静的データメンバ、インスタンス、ないし、静的関数、静的コンストラクタ、インスタンス、ないし、静的プロパティ、インスタンス、ないし、静的イベント、演算子関数、または任意の種類のネスト型であるべきです。
インターフェイスはインスタンス・データ・メンバ、インスタンス・コンストラクタ、ないし、ファイナライザを含むべきではありません。
インターフェイス・メンバは public アクセス権を持ちます。
明示的に public アクセス指定子を与えることは冗長となりますが、許されています。他のアクセス指定子はインターフェイス・メンバ宣言に使われるべきではありません。
インターフェイス中で宣言された全てのインスタンス・メンバは暗黙のうちに abstract です。
しかしながら、それらのメンバは、virtual と abstract 修飾子か、virtual 修飾子と
pure-specifier(純粋指定子) を冗長となりますが含むことができます。
[例:
interface class I {
property int Size { ... } // (暗黙の) abstract プロパティ
virtual property string Name abstract = 0 { ... }
// "virtual", "abstract", "=0" の記述は許されているが
// 冗長となります。
};
]
インターフェイス・クラスは friend 宣言するべきではありません。
インターフェイスを実装するクラスはそのインターフェイスの全てのメンバに定義を与えるべきです。
インターフェイスはその全ての静的メンバの定義を提供するべきでしょう。
いくつかのインターフェイス・クラスメンバ宣言、メンバ・アクセス、そして、メンバ関数はメタデータ生成の間に特別な扱いを要請します。
詳細に関しては
§34.9を参照のこと。
25.2.1 関数
インターフェイス・インスタンス関数宣言は関数定義されるべきではありません。
もし、関数が virtual 宣言されていたら、それは abstract 宣言などもされているべきでしょう。
インターフェイス・インスタンス関数は暗黙のうちに abstract です。
インターフェイスのメンバ関数は
cv-qualifier-seq を持つべきではありません。
インターフェイス・クラス中のメンバ関数はオプションとして、
parameter-array(パラメータ配列)(
§18.4)を
parameter-declaration-clause(パラメータ宣言節)中に持つことができます。
[注記:それぞれのインターフェイス・クラスに、実装はいくつかの名前が予約済みです。(
§19.2.3)]
[注記:インターフェイス・クラスのメンバ関数は hidebysig 名前検索(
§10.7)を使います。]
25.2.2 プロパティ
インターフェイス・クラスはプロパティ(
§19.5)をサポートします。
インターフェイス・プロパティ定義のアクセサ関数は、インターフェイスのインスタンス・アクセサ関数は定義されることなく宣言されるべきである点を除いて、クラス・プロパティ定義(
§19.5.3)のアクセサ関数に対応します。
故に、アクセサ関数は単純にプロパティが read-write か、read-only か、write-only であるかどうかを示すものです。
[例:
interface class I {
property int Size { int get(); void set(int value); }
proeprty bool default[int] {
bool get(int); void set(int k, bool value); }
};
]
(
accessor-specification(アクセサ指定子)が括弧終端であるのに対して)セミコロンで終了する
property-definition(プロパティ定義)はトリビアル・スカラー・プロパティ(
§19.5.5)を宣言します。
そのようなインスタンス宣言は get と set のアクセサ関数を持つ抽象仮想プロパティを宣言します。
インターフェイス中にインライン定義を持つアクセサ関数は不正です。
[注意:それぞれのプロパティ定義ごとに、実装はいくつかの名前を予約済みです。(
§19.2.1)]
25.2.3 イベント
インターフェイス・クラスはイベント(
§19.6)をサポートします。
インターフェイス・イベント宣言のアクセサ関数は、インスタンス・アクセサ関数は、定義されない宣言である点を除いてクラス・イベント定義のアクセサ関数(
§19.6.2)に対応します。
インターフェイスのイベントは持ち上げアクセサ関数を持つことができない(なぜなら、全てのインターフェイスメンバは public だから)ので、そのようなイベントは関数呼び出し構文を使って呼び出すことはできません。
[注意:それぞれのイベント定義ごとに、実装はいくつかの名前を予約済みです。(
§19.2.2)]
25.2.4 デリゲート型
インターフェイス・クラスは
delegate-specifiers(デリゲート指定子)(
§27.1)をサポートします。
25.2.5 メンバ・アクセス
インターフェイス・メンバの検索の詳細は
§10.7参照のこと。
25.2.6 デストラクタとファイナライザ
インターフェイス・クラスはデストラクタ(
§19.13)宣言を許します。
しかしながら、インターフェイス・クラスはファイナライザ(
§19.13)を宣言すべきではありません。
メタデータの詳細は、
§34.7.13.2と
§34.7.13.3を参照のこと。
25.3 インターフェイス実装
インターフェイスはクラスによって実装されることができます。
クラスがインターフェイスを実装することを示すために、インターフェイス識別子はクラスの基底クラス・リストに含まれます。[例:
interface class ICloneable {
Object^ Clone();
};
interface class IComparable {
int CompareTo(Object^ other);
};
ref class ListEntry : ICloneable, IComparable {
public:
virtual Object^ Clone() { ... }
virtual int CompareTo(Object^ other) { ... }
};
]
基底クラス・リストのインターフェイスはいつも、そして、暗黙のうちに public です。
public キーワードはインターフェイスの base-class access specifier (基底クラス・アクセス指定子)としてあってもかまいませんが、必須ではありません。
もし、インターフェイスの base class specifier (基底クラス・アクセス指定子)として private, protected ないし、virtual キーワードが含まれているプログラムは不正です。
インターフェイスを継承したクラスは、また、暗黙のうちにインターフェイスの基底となるインターフェイス全ての実装を行います。
これは例えクラスがその基底クラス・リストに全ての基底インターフェイスを明示的にリストしていなくても、真となります。[例:
interface class IControl {
void Paint();
}
interface class ITextBox : IControl {
void SetText(String^ text);
};
ref class TextBox : ITextBox {
public:
virtual void Paint() { ... }
virtual void SetText(String^ text) { ... }
};
ここにある、クラス TextBox は IControl と ITextBox の双方を実装します。]
インターフェイス関数は上書きされるのでなく実装されるので、ref クラスの仮想関数上書きルールはインターフェイスの実装ルールと直交します。
クラスはもし基底クラスがすでにインターフェイスを実装していれば、インターフェースを実装します。そして、もし、基底クラスが実装していなければ、クラスはインターフェイスの全ての関数を実装するべきです。
関数 IF を持つインターフェイス I を実装するクラス R について、関数 F は次のような手群に従ってインターフェイスを実装します。
- F は名前 I::IF に直接名前付け上書き構文をつかっているか、そうでなければ、
- シグネイチャ F は IF と同じで、F が public である。
もし、R 中に IF を実装する手順で一つの関数も見あたらなければ、F は R の基底クラスから public 仮想関数となることができます。
もし、F が virtual マークされていなければ、それはインターフェイス関数を実装しません。
関数 F は abstract になることができます。
R は IF を実装しない同じ名前の IF として(仮想、非仮想)関数を導入できます。
[注意:これは他の関数が名前付け上書き構文を使用した場合に起きます。]
[例:
public interface struct I1 {
void F();
};
public interface struct I2 : I1 {
void G();
void K();
};
public ref struct B {
virtual void K() { ... }
};
public ref struct D : B, I2 {
virtual void F() { ... } // I1::F の実装
virtual void H() = I2::G { ... } // I2::G の実装
virtual void G() new { ... } // 新しい G
// I2::K は B::K で実装される
};
public ref struct E abstract : I1 {
virtual void F() abstract;
};
]
インターフェイスを継承する refクラスか値クラスはそのインターフェイスから全てのメンバを実装することを要請されます。
これは
implementing the interface(インターフェイスの実装)と呼ばれます。継承したインターフェイスの実装をしていないクラスは不正です。
[注意:インターフェイス関数は実装されるのであって、上書きされるわけではありません。
そのため、インターフェイスを実装しないクラスは基底クラスからの抽象関数が上書きされていなくても暗黙のうちに abstract にはなりません。