COM インターフェイスとは
C# または Java がわかっている場合、インターフェイスは使い慣れた概念である必要があります。 インターフェイスは、実装について何も指示することなく、オブジェクトがサポートできる一連のメソッドを定義 します 。 インターフェイスは、メソッドを呼び出すコードと、 メソッドを実装するコードの間の明確な境界をマークします。 コンピューター サイエンスの用語では、呼び出し元は実装から 切り離されます 。
C++ では、インターフェイスに最も近いものは純粋仮想クラスです。つまり、純粋な仮想メソッドのみを含み、他のメンバーを含まないクラスです。 インターフェイスの仮定の例を次に示します。
// The following is not actual COM.
// Pseudo-C++:
interface IDrawable
{
void Draw();
};
この例の考え方は、一部のグラフィックス ライブラリ内のオブジェクトのセットが描画可能であるということです。 インターフェイスは IDrawable
、描画可能なオブジェクトがサポートする必要がある操作を定義します。 (慣例により、インターフェイス名は "I" で始まります)。この例では、インターフェイスによって IDrawable
1 つの操作が定義されます。 Draw
すべてのインターフェイスは 抽象であるため、プログラムはオブジェクトのインスタンスを IDrawable
作成できませんでした。 たとえば、次のコードはコンパイルされません。
IDrawable draw;
draw.Draw();
代わりに、グラフィックス ライブラリには、 インターフェイスを 実装 するオブジェクトが IDrawable
用意されています。 たとえば、ライブラリは図形を描画するための図形オブジェクトと、イメージを描画するためのビットマップ オブジェクトを提供する場合があります。 C++ では、これは共通の抽象基本クラスから継承することによって行われます。
class Shape : public IDrawable
{
public:
virtual void Draw(); // Override Draw and provide implementation.
};
class Bitmap : public IDrawable
{
public:
virtual void Draw(); // Override Draw and provide implementation.
};
クラスと Bitmap
クラスはShape
、2 つの異なる種類の描画可能オブジェクトを定義します。 各クラスは を IDrawable
継承し、 メソッドの独自の実装を Draw
提供します。 当然、2 つの実装は大きく異なる場合があります。 たとえば、 メソッドは Shape::Draw
一連の線をラスター化し、ピクセル Bitmap::Draw
の配列を blit します。
このグラフィックス ライブラリを使用するプログラムでは、 または ポインターを直接使用するのではなく、ポインターを介して IDrawable
Shape
オブジェクトと Bitmap
Bitmap
オブジェクトを操作Shape
します。
IDrawable *pDrawable = CreateTriangleShape();
if (pDrawable)
{
pDrawable->Draw();
}
ポインターの配列 IDrawable
をループする例を次に示します。 配列内の各オブジェクトが を継承 IDrawable
している限り、配列にはさまざまな図形、ビットマップ、およびその他のグラフィックス オブジェクトが含まれる場合があります。
void DrawSomeShapes(IDrawable **drawableArray, size_t count)
{
for (size_t i = 0; i < count; i++)
{
drawableArray[i]->Draw();
}
}
COM の重要なポイントは、呼び出し元のコードに派生クラスの型が表示されない点です。 言い換えると、型 Shape
の変数や Bitmap
コード内で宣言することはありません。 図形とビットマップに対するすべての操作は、ポインターを使用して IDrawable
実行されます。 このように、COM はインターフェイスと実装の間で厳密な分離を維持します。 クラスと Bitmap
クラスの実装のShape
詳細は、たとえば、バグを修正したり、新しい機能を追加したりするために変更される可能性があり、呼び出し元のコードは変更されません。
C++ 実装では、インターフェイスはクラスまたは構造体を使用して宣言されます。
注意
このトピックのコード例は、実際のプラクティスではなく、一般的な概念を伝えるために用意されています。 新しい COM インターフェイスの定義は、このシリーズの範囲を超えていますが、ヘッダー ファイルでインターフェイスを直接定義することはできません。 代わりに、COM インターフェイスは、インターフェイス定義言語 (IDL) と呼ばれる言語を使用して定義されます。 IDL ファイルは、C++ ヘッダー ファイルを生成する IDL コンパイラによって処理されます。
class IDrawable
{
public:
virtual void Draw() = 0;
};
COM を使用する場合は、インターフェイスがオブジェクトではないことに注意することが重要です。 これらは、オブジェクトが実装する必要があるメソッドのコレクションです。 と の例に示すように、複数のオブジェクトで同じインターフェイスをShape
Bitmap
実装できます。 さらに、1 つのオブジェクトで複数のインターフェイスを実装できます。 たとえば、グラフィックス ライブラリでは、グラフィックス オブジェクトの保存と読み込みをサポートする という名前 ISerializable
のインターフェイスを定義できます。 次に、次のクラス宣言について考えてみましょう。
// An interface for serialization.
class ISerializable
{
public:
virtual void Load(PCWSTR filename) = 0; // Load from file.
virtual void Save(PCWSTR filename) = 0; // Save to file.
};
// Declarations of drawable object types.
class Shape : public IDrawable
{
...
};
class Bitmap : public IDrawable, public ISerializable
{
...
};
この例では、 クラスは を Bitmap
実装します ISerializable
。 プログラムでは、このメソッドを使用してビットマップを保存または読み込むことができます。 ただし、 クラスは を Shape
実装 ISerializable
していないため、その機能は公開されません。 次の図は、この例の継承関係を示しています。
このセクションでは、インターフェイスの概念的な基礎を調べましたが、これまでに実際の COM コードは見ていません。 まず、COM アプリケーションで行う必要がある最初の操作として、COM ライブラリを初期化します。