Win32 App What Is a COM Interface - yoshimune/LearningDirectX11 GitHub Wiki

This page refers to 【What Is a COM Interface?

もしC#にかJavaについて知っているなら、インターフェイスについて知っているはずです。インターフェイスはオブジェクトがサポートするメソッドセットを、実装を抜きにして定義します。インターフェイスはメソッドを呼び出すコードとメソッドを実装するコードの教会を明確に示します。コンピュータ・サイエンスのテーマでは、呼び出し側は実装から分離されています。

C++では、インターフェイスに近いものは純粋なvirtualクラス(純粋なvirtualメソッドのみを含むクラス)です。以下はインターフェイスの仮説的な例です。

// The following is not actual COM.

// Pseudo-C++:

interface IDrawable
{
    void Draw();
};

この例のアイディアはいくつかの描画可能グラフィックスライブラリ内のオブジェクトセットです。IDrawableインターフェイスはいくつかの描画可能オブジェクトがサポートしなくてはならないオペレーションを定義します。(規約では、インターフェイス名は"I"から始めます。)この例では、IDrawbleインターフェイスは単一のオペレーションDrawを定義しています。

全てのインターフェイスは abstract ですよってプログラムはIDrawableのインスタンスを作成できません。例えば、以下のコードはコンパイルエラーになります。

IDrawable draw;
draw.Draw();

代わりに、グラフィックライブラリはIDrawableインターフェイスが実装されたオブジェクトを提供します。例えば、ライブラリはshapeオブジェクトとbitmapオブジェクトを描画のために提供します。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.
};

ShapeBitmapクラスはdrawableオブジェクトの2つの明確な形式を定義します。各々のクラスはIDrawableから継承されます。また、各自のDrawメソッドの実装を提供します。当然、2つの実装はかなり違っているかもしれません。例えば、Shape:Drawメソッドは線のラスタライズをし、一方でBitmap::Drawはピクセル配列をblitするかもしれません。

プログラムはグラフィックスライブラリを使ってShapeBitmapオブジェクトを通して、ShapeBitmapのポインタを直接扱うのではなく、IDrawableポインタを操作します。

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はインターフェイスと実装の厳格な分離を維持します。呼び出し側のコードを変更することなく、ShapeBitmapの実装を変更する(たとえば、バグ修正や機能追加など)ことができます。

C++の実装では、インターフェイスはクラスか構造体を使って宣言します。

このトピックでのサンプルコードは、一般的な概念を伝えるためのもので、実際の慣習ではありません。新しいCOMインターフェイスを定義することは、このシリーズの責任範囲を超えています。しかし、ヘッダーファイルに直接インターフェイスを定義することはありません。代わりに、COMインターフェイスはInterface Definition Language(IDL)と呼ばれるものを使って定義されます。IDLファイルはIDLコンパイラで処理され、C++のヘッダファイルを生成します。

class IDrawable
{
public:
    virtual void Draw() = 0;
}

COMを利用するとき、重要なのは「インターフェイスはオブジェクトではない」ということを覚えておくことです。インターフェイスは、オブジェクトが実装しなくてはならないメソッドの集合です。いくつかのオブジェクトは、ShapeBitmapの例で見せたように、同じインターフェイスを実装できます。更に、一つのオブジェクトはいくつかのインターフェイスを実装することができます。例えば、グラフィックライブラリはグラフィックオブジェクトのセーブとロードを行うISerializableインターフェイスを定義している場合があります。
次のクラス宣言を考えてみましょう。

// An interface for serialisation
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を実装していません。よって、機能を公開していません。

Next:Win32 App Initializing the COM Library