目次
2 つ目は、インターフェイスと継承 (IInterface と Inheritance)
3. インターフェースの識別と GUID (インターフェースの識別と GUID)
オブジェクト インターフェイス (略してインターフェイス) は、クラスが実装できるメソッドを定義します。インターフェイスはクラスとして宣言されますが、直接インスタンス化することはできず、独自のメソッド定義を持ちません。代わりに、インターフェイスのメソッドの実装を提供するのは、インターフェイスをサポートするクラスの責任です。インターフェイス型の変数は、インターフェイスを実装するクラスのオブジェクトを参照できますが、呼び出せるのはインターフェイス内で宣言されたメソッドのみです。
インターフェイスには多重継承の利点がいくつかありますが、セマンティックな問題はありません。インターフェイスは、SOAP などの分散オブジェクト モデルを使用する場合にも不可欠です。分散オブジェクト モデルを使用すると、インターフェイスをサポートするカスタム オブジェクトは、C++、Java、およびその他の言語で記述されたオブジェクトと対話できます。
1. インターフェースの種類
クラスと同様、インターフェイスはプログラムまたはユニットの最も外側のスコープ内でのみ宣言でき、ストアド プロシージャや関数の宣言内では宣言できません。インターフェイス型の宣言は次の形式になります。
type interfaceName = interface (ancestorInterface) ['{GUID}'] memberList end;
警告: Win32 COM 相互運用性をサポートするには、ancestorInterfaceおよびGUID仕様が必要です。COM 経由でインターフェイスにアクセスする場合は、ancestorInterfaceとGUIDを必ず指定してください。
インターフェイス宣言はほとんどの点でクラス宣言と似ていますが、次の制限があります。
- メンバー リストにはメソッドとプロパティのみを含めることができます。インターフェイスではフィールドは許可されません。
- インターフェイスにはフィールドがないため、プロパティの読み取り/書き込み仕様はメソッドである必要があります。
- インターフェイスのすべてのメンバーはパブリックです。可視性指定子と記憶域指定子は使用できません。(ただし、配列プロパティはデフォルトとして宣言できます)。
- インターフェイスにはコンストラクターやデストラクターはありません。これらは、そのメソッドを実装するクラスを介さない限りインスタンス化できません。
- メソッドを virtual、dynamic、abstract、または override ( virtual、dynamic、abstract、またはoverride )として宣言することはできません。インターフェイスは独自のメソッドを実装していないため、これらの名前には何の意味もありません。
以下にインターフェース宣言の例を示します。
type IMalloc = interface(IInterface)
['{00000002-0000-0000-C000-000000000046}']
function Alloc(Size: Integer): Pointer; stdcall;
function Realloc(P: Pointer; Size: Integer): Pointer; stdcall;
procedure Free(P: Pointer); stdcall;
function GetSize(P: Pointer): Integer; stdcall;
function DidAlloc(P: Pointer): Integer; stdcall;
procedure HeapMinimize; stdcall;
end;
一部のインターフェイス宣言では、インターフェイスの予約語が dispinterface に置き換えられます。
2 つ目は、インターフェイスと継承 (IInterface と Inheritance)
インターフェイスは、クラスと同様に、その祖先のすべてのメソッドを継承します。ただし、クラスとは異なり、インターフェイスはメソッドを実装しません。インターフェイスが継承するのはメソッドを実装する義務であり、その義務はインターフェイスをサポートするクラスに渡されます。
インターフェイスの宣言では、祖先インターフェイスを指定できます。祖先インターフェイスが指定されていない場合、それは IInterface の直接の子孫になります。IInterface はシステム ユニットで定義され、他のすべてのインターフェイスの最終的な祖先です。Win32 では、IInterface は QueryInterface、_AddRef、および _Release の 3 つのメソッドを宣言します。
注: IInterface は IUnknown と同等です。一般に、プラットフォームに依存しないアプリケーションは IInterface を使用する必要がありますが、Win32 依存関係を持つ特定のプログラムは IUnknown のままにする必要があります。
QueryInterface は、オブジェクトによってサポートされるさまざまなインターフェイスへの参照を取得するメソッドを提供します。_AddRef と _Release は、インターフェイス参照の生涯メモリ管理を提供します。これらのメソッドを実装する最も簡単な方法は、System ユニットの TInterfacedObject から実装クラスを派生することです。これらのメソッドを空の関数として実装することもできますが、COM オブジェクトは _AddRef および _Release を通じて管理する必要があります。
警告: Win32 COM 相互運用性をサポートするには、QueryInterface、_AddRef、および _Release が必要です。COM 経由でインターフェイスにアクセスする場合は、必ずこれらのメソッドを実装してください。
3. インターフェースの識別と GUID (インターフェースの識別と GUID)
インターフェイス宣言では、メンバー リストの前に括弧で囲まれたリテラル文字列で表されるグローバル一意識別子 (GUID) を指定できます。宣言の GUID 部分は次の形式にする必要があります。
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']
ここで、各 x は 16 進数 (0 ~ 9 または A ~ F) です。タイプ ライブラリ エディタは、新しいインターフェイスの GUID を自動的に生成します。コード エディターで Ctrl+Shift+G を押して GUID を生成することもできます。
GUID は、インターフェイスを一意に識別する 16 バイトのバイナリ値です。インターフェイスに GUID がある場合、インターフェイス ルックアップを使用してその実装への参照を取得できます。
注: GUID は COM の相互運用性のためにのみ使用されます。
システムユニットで宣言された TGUID および PGUID タイプは、GUID を操作するために使用されます。
type
PGUID = ^TGUID;
TGUID = packed record
D1: Cardinal;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;
end;
次の 2 つの呼び出し方法がサポートされています。
if Supports(Allocator, IMalloc) then ...
または
if Supports(Allocator, IID_IMalloc) then ...
注: SysUtils ユニットは、クラス型とインスタンスが GUID で表される特定のインターフェイスをサポートする場合に true または false を返すSupportsという名前のオーバーロードされた関数を提供します。Supports関数は、Delphi と同じ方法で演算子として使用されます。違いは、Supports 関数の右側のオペランドは GUID または GUID に関連付けられたインターフェイス型であるのに対し、is および as オペランドの右側のオペランドは型名であることです。is と as の詳細については、「クラスリファレンス」を参照してください。
4. インターフェースの呼び出し規約
インターフェイス メソッドのデフォルトの呼び出し規則は register ですが、モジュール間で共有されるインターフェイス (特に、異なる言語で書かれたインターフェイス) は、stdcall を使用してすべてのメソッドを宣言する必要があります。Win32 では、safecall を使用してデュアル インターフェイスのメソッドを実装できます。
5. インターフェースのプロパティ
インターフェイスで宣言されたプロパティには、クラス型変数ではなく、インターフェイス型の式を介してのみアクセスできます。また、インターフェイスのプロパティは、インターフェイスがコンパイルされたプログラムでのみ表示されます。
インターフェイスでは、フィールドが使用できないため、プロパティの読み取りおよび書き込み仕様はメソッドである必要があります。
6. 事前申告
予約語インターフェイスとセミコロンで終わるインターフェイス宣言は、祖先、GUID、またはメンバー リストが指定されていない場合、前方宣言になります。前方宣言は、同じ型宣言セクション内の同じインターフェイスの定義宣言によって解決される必要があります。つまり、前方宣言と定義宣言の間には、他の型宣言以外の宣言を含めることはできません。
前方宣言により、相互依存インターフェイスが可能になります。例えば:
type
IControl = interface;
IWindow = interface
['{00000115-0000-0000-C000-000000000044}']
function GetControl(Index: Integer): IControl;
//. . .
end;
IControl = interface
['{00000115-0000-0000-C000-000000000049}']
function GetWindow: IWindow;
//. . .
end;
相互に派生したインターフェイスは許可されません。たとえば、IControl から IWindow を派生したり、IWindow から IControl を派生したりすることは違法です。