オブジェクト インターフェイス(Object Pascal)

提供: Appmethod Topics
移動先: 案内検索

オブジェクト インターフェイス:インデックス への移動


オブジェクト インターフェイス(または単にインターフェイス)は、クラスに実装させることができるメソッドを定義します。インターフェイスはクラスと同じように宣言しますが、直接インスタンス化することはできません。また、インターフェイスが個々のメソッド定義を持つことはありません。つまり、インターフェイスをサポートするクラス側でインターフェイス メソッドの実装を提供する必要があります。インターフェイス型の変数は、オブジェクトのクラスがそのインターフェイスを実装している場合にオブジェクトを参照できますが、このような変数を使って呼び出すことができるのは、そのインターフェイスで宣言されたメソッドだけです。

インターフェイスを使用すると、意味上の難しさを回避しながら多重継承のメリットの一部を得ることができます。また、SOAP のような分散オブジェクト モデルを使用する場合にも重要な役割を果たします。インターフェイスをサポートするカスタム オブジェクトは、分散型オブジェクトを使用して、C++ や Java などの言語で書かれたオブジェクトと相互通信できます。

インターフェイス型

インターフェイスは、クラスの場合と同様に、プログラムやユニットの一番外側のスコープでのみ宣言できます。手続きや関数内では宣言ではできません。インターフェイス型の宣言は、次の形式で記述します。

 type interfaceName = interface (ancestorInterface) ['{GUID}'] memberList end;


インターフェイス宣言はクラス宣言とそれほど変わりませんが、次の制限事項があります。

  • メソッドとプロパティのみ memberList に指定できる。フィールドをインターフェイスで使用できない。
  • インターフェイスにはフィールドがないため、プロパティの read 指定子と write 指定子をメソッドにする必要がある。
  • インターフェイスのメンバはすべて public となる。可視性指定子と格納指定子は使用できない (ただし、配列プロパティは default として宣言できる)。
  • インターフェイスにはコンストラクタとデストラクタがない。インターフェイスのメソッドを実装しているクラスを使用する以外は、インターフェイスのインスタンス化はできない。
  • メソッドは virtualdynamicabstractoverride として宣言できない。インターフェイス自体はメソッドを実装していないため、これらの宣言に意味はない。

次に、インターフェイスの宣言の例を示します。

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;

インターフェイスの宣言によっては、interface の予約語の代わりに dispinterface が使用されます。

IInterface と継承

インターフェイスは、クラスと同じように自身の上位インターフェイスのメソッドをすべて継承します。ただし、メソッドを実装しない点がクラスとは異なります。インターフェイスが継承するものは、メソッドの実装の必要性で、そのインターフェイスをサポートするすべてのクラスに渡されます。

インターフェイスを宣言するときは、上位インターフェイスを指定できます。上位インターフェイスを指定しない場合、そのインターフェイスは IInterface の直下の下位インターフェイスとして位置づけられます。IInterface は、System ユニットに定義されており、他のすべてのインターフェイスの最上位に位置づけられています。Win32 では、IInterface に 、QueryInterface_AddRef、および _Release の 3 つのメソッドを宣言します。

メモ: IInterfaceIUnknown と同等です。一般的には、プラットフォームに依存しないアプリケーションに IInterface を使用し、Win32 に依存する部分があるプログラムには IUnknown を使用する必要があります。

QueryInterface は、オブジェクトがサポートしている各インターフェイスを参照するための手段を提供します。_AddRef_Release は、インターフェイス参照の存続期間のメモリ管理に使用されます。これらのメソッドを実装するときは、System ユニットの TInterfacedObject から実装クラスを派生させる方法が最も簡単です。また、どのメソッドも空の関数として実装することで破棄できます。


インターフェイスの識別と GUID

インターフェイス宣言では、GUID(グローバル一意識別子)を指定できます。GUID は、メンバ リスト直前の角かっこで囲んだ文字列リテラルで表現されます。宣言の GUID 部は、次の形式にする必要があります。

 ['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']

各 x は 1 桁の 16 進数(0 ~ 9、A ~ F)です。タイプ ライブラリ エディタでは、新しいインターフェイスの GUID が自動的に生成されます。コード エディタで Ctrl+Shift+G を押しても GUID を生成できます。

GUID は、インターフェイスを一意に識別する 16 バイトのバイナリ値です。インターフェイスが GUID を持つ場合は、インターフェイス問い合わせを使用してその実装への参照を取得できます。

System ユニットで宣言される TGUID 型と PGUID 型は、GUID の操作に使用します。

 type 
     PGUID = ^TGUID;
     TGUID = packed record
       D1: Cardinal;
       D2: Word;
       D3: Word;
       D4: array[0..7] of Byte;
   end;

Supports は次の 2 つの方法で呼び出せます。

if Supports(Allocator, IMalloc) then ...

または

if Supports(Allocator, IID_IMalloc) then ...

メモ: SysUtils ユニットでは、Supports というオーバーロード関数を使用できます。この関数は、クラスの型とインスタンスが GUID で表現される特定のインターフェイスをサポートするときに、true または false を返します。Supports 関数は、Object Pascal の is 演算子および as 演算子と同じ方法で使用します。重要な相違点は、Supports 関数が GUID か GUID に関連付けられたインターフェイス型のどちらかを右オペランドとして取れるのに対して、isas は型の名前を取ることです。is 演算子および as 演算子の詳細は、「クラス参照」を参照してください。

インターフェイスの呼び出し規約

インターフェイス メソッドのデフォルトの呼び出し規約は register ですが、インターフェイスがモジュール間で共有されている場合、特にモジュールが異なる言語で記述されている場合は、すべてのメソッドを stdcall で宣言する必要があります。Win32 では、safecall を使用して、デュアル インターフェイスのメソッドを実装できます。

インターフェイスのプロパティ

インターフェイスで宣言されたプロパティは、インターフェイス型の式を介してのみアクセスできます。クラス型変数からはアクセスできません。また、インターフェイスのプロパティは、インターフェイスがコンパイルされているプログラムの中からのみ参照できます。

インターフェイスではフィールドを使用できないため、プロパティの read 指定子と write 指定子をメソッドにする必要があります。

前方宣言

インターフェイスの宣言が予約語 interface とセミコロンだけで終わっており、上位インターフェイス、GUID、メンバ リストの指定が省略されている場合、その宣言は前方参照宣言になります。前方参照宣言は、同じ型宣言セクションの中で同じインターフェイスの宣言を定義することによって解決する必要があります。つまり、前方宣言とその定義宣言の間には、他の型宣言しか含められません。

forward 宣言を使用することで、相互に依存したインターフェイスを使用できるようになります。たとえば、次のようになります。

 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 を派生させることはできません。

関連項目