インターフェイス
InterfaceDeclaration:
interface Identifier BaseInterfaceListopt InterfaceBody
InterfaceTemplateDeclaration
BaseInterfaceList:
: InterfaceClasses
InterfaceBody:
{ DeclDefsopt }
インターフェイスは、そのインターフェイスを継承する関数が 必ず実装する必要のある関数のリストを記述したものです。 インターフェイスを実装したクラスへの参照は、 そのインターフェイスへの参照へと変換できます。
Win32のCOM/OLE/ActiveXのような、 ある種のOSのシステムオブジェクトは特別なinterfaceを提供しています。Dのインターフェイスで COM/OLE/ActiveX と互換性を持つものは COM Interfaces と呼ばれます。
C++ Interfaces は、 C++とのバイナリ互換性のために提供される別の形のインターフェイスです。
インターフェイスは、クラスから派生することはできません。 派生元は他のインターフェイスに限られます。クラスは、同じインターフェイスを複数回継承することはできません。
interface D
{
void foo();
}
class A : D, D // エラー、インターフェイスの重複
{
}
インターフェイスのインスタンスは作成できません。
interface D
{
void foo();
}
...
D d = new D(); // エラー、インターフェイスのインスタンスは作成不可
インターフェイスのvirtualメンバ関数は実装を持ちません。 static関数やfinal関数の実装はinterfaceに記述します。
interface D
{
void bar() { } // エラー、実装を書くことはできない
static void foo() { } // ok
final void abc() { } // ok
}
インターフェイスを継承したクラスで、 インターフェイスのfinalやstaticメンバ関数をオーバーライドはできません。
interface D {
void bar();
static void foo() { }
final void abc() { }
}
class C : D {
void bar() { } // ok
void foo() { } // エラー、static D.foo() はオーバーライドできない
void abc() { } // エラー、final D.abc() はオーバーライドできない
}
インターフェイス関数は、 それを継承するクラスで全て定義されている必要があります:
interface D
{
void foo();
}
class A : D
{
void foo() { } // ok, 実装を提供している。
}
class B : D
{
int foo() { } // エラー, void foo() の実装がない。
}
インターフェイスは継承して、関数をオーバーライドできます:
interface D
{
int foo();
}
class A : D
{
int foo() { return 1; }
}
class B : A
{
int foo() { return 2; }
}
...
B b = new B();
b.foo(); // 2 を返す
D d = cast(D) b; // ok, B は AによるDの実装を継承しているので。
d.foo(); // 2 を返す
インターフェイスは、派生クラスで再実装可能です:
interface D
{
int foo();
}
class A : D
{
int foo() { return 1; }
}
class B : A, D
{
int foo() { return 2; }
}
...
B b = new B();
b.foo(); // 2 を返す
D d = cast(D) b;
d.foo(); // 2 を返す
A a = cast(A) b;
D d2 = cast(D) a;
d2.foo(); // 2 を返す。BのDではなくAのDに見えるけれど。
インターフェイスを再実装するには、その全ての関数を実装しなければなりません。 基底クラスからの継承はされません:
interface D
{
int foo();
}
class A : D
{
int foo() { return 1; }
}
class B : A, D
{
} // エラー、インターフェイス D のための foo() が無い
契約付きインターフェイス
インターフェイスのメンバ関数には、body はありませんが、 事前条件・事後条件の契約を記述できます。これらの契約は、 インターフェイスを継承したクラスに全て継承されます。
interface I
{
int foo(int i)
in { assert(i > 7); }
out (result) { assert(result & 1); }
void bar();
}
const/immutable インターフェイス
インターフェイスが記憶域クラス const か immutable で修飾されていた場合、 その全てのメンバが const か immutable 記憶域クラスは継承されません。
COM インターフェイス
インターフェイスの一種として、COMインターフェイスがあります。COMインターフェイスは、 WindowsのCOMオブジェクトとして直接適合するように設計されます。全ての COM オブジェクトは COMインターフェイスによって表現でき、COMインターフェイスを持つ全ての D言語のオブジェクトは、外部のCOMクライアントから使用できます。
COMインターフェイスは、std.c.windows.com.IUnknown から派生することで定義します。COMインターフェイスは、 D言語の通常のインターフェイスと以下の点で異なります:
- std.c.windows.com.IUnknown から派生している。
- DeleteExpression の引数として使えない。
- 参照は、周囲のクラスのオブジェクトへのUpcastや、 派生インターフェイスへのDowncastをすることが許されない。 この目的には、COMの標準的なやり方で適切な QueryInterface() が実装されていなければなりません。
- COMインターフェイスから派生したクラスはCOMクラスです。
- COMクラスのメンバ関数のデフォルトのリンケージは is extern(System) です
- vtbl[] の先頭のメンバは InterfaceInfo へのポインタではなく、最初の仮想関数ポインタになります。
さらに詳しい情報については Modern COM Programming in D をご覧下さい。
C++インターフェイス
C++のリンケージで宣言されたインターフェイスはC++インターフェイスになります:
extern (C++) interface Ifoo
{
void foo();
void bar();
}
これは以下のC++での宣言に対応します:
class Ifoo
{
virtual void foo();
virtual void bar();
};
C++インターフェイスから派生したインターフェイスも全て、 C++インターフェイスになります。 C++インターフェイスは、以下の点でDのインターフェイスと異なります:
- DeleteExpression の引数にできない
- 参照を外部クラスのオブジェクトへアップキャストすることや、 派生インターフェイスへダウンキャストすることができません。
- メンバ関数の呼び出し規約のデフォルトが、 DではなくC++の規約になります。
- vtbl[] の先頭メンバが Interface へのポインタではなく、先頭の仮想関数ポインタとなります。