2006 年 12 月 4 日 22 時 31 分

テンプレートクラスのインスタンス


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


テンプレートクラスは、定義しただけでは何の効果もない。
テンプレートの引数に具体的なクラス型を与えることで、
テンプレートを元にしたクラスの実体が定義される。
これを、「テンプレートのインスタンス化」と呼ぶ。

では、DllGetClassObject を書き換えて、
他の 2 クラスも公開できるように修正する。
どうせなら、HardLinkIconID にもテンプレートを使おう。

=========== library.cpp ==========

#include "global.hpp"

#include "HardLinkIconID.hpp"
#include "MountPointIconID.hpp"
#include "FolderLinkIconID.hpp"
#include "ClassObject.hpp"

// (…DllMain…)

STDAPI DllGetClassObject(
        /* [in] */ REFCLSID rclsid,
        /* [in] */ REFIID riid,
        /* [out] */ void** ppvObject) {

    // クラスオブジェクトの唯一のインスタンス
    static ClassObject<HardLinkIconID> hardLinkClass;
    static ClassObject<MountPointIconID> mountPointClass;
    static ClassObject<FolderLinkIconID> folderLinkClass;

    // ppvObject が NULL なら例外
    if (ppvObject == NULL) return E_INVALIDARG;

    // ppvObject は out なので、
    // ポインタが指す元の値は無視できる
    *ppvObject = NULL;

    IUnknown* classObject = NULL;

    // 対応するクラスオブジェクトを取得
    if (IsEqualCLSID(rclsid, CLSID_HardLinkIconID)) {
        classObject = &hardLinkClass;
    } else if (IsEqualCLSID(rclsid, CLSID_MountPointIconID)) {
        classObject = &mountPointClass;
    } else if (IsEqualCLSID(rclsid, CLSID_FolderLinkIconID)) {
        classObject = &folderLinkClass;
    } else {
        return CLASS_E_CLASSNOTAVAILABLE;
    }

    // クラスオブジェクトへの参照を追加
    classObject->AddRef();

    // インタフェースを要求
    HRESULT result = classObject->QueryInterface(riid, ppvObject);

    // 参照を解放
    classObject->Release();

    return result;

}

=========== end of library.cpp ==========

ClassObject<HardLinkIconID> という記述によって、
HardLinkIconID を実引数として
ClassObject テンプレートがインスタンス化され、
ClassObject<HardLinkIconID> というクラスが定義される。

これは通常の型と同じように扱われるので、
型が必要な箇所で自由に使うことができる。

C++ のテンプレートは柔軟であり、
テンプレートを基にした型が 1 度でも使われると、
自動的にインスタンス化してくれる。
そのため、実体がどこで定義されるかは考える必要はない。

あとは、新たに追加で作成した 2 クラスに対応した、
クラス ID を作成し、global.[ch]pp に追加しよう。

========== global.hpp ==========

#ifndef global_hpp_included
#define global_hpp_included

#define STRICT
#define UNICODE
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <ole2.h>

// グローバル変数
extern HMODULE g_moduleHandle;
extern volatile long g_serverLockCount;

// グローバル定数
extern const GUID CLSID_HardLinkIconID;
extern const GUID CLSID_MountPointIconID;
extern const GUID CLSID_FolderLinkIconID;

#endif // !global_hpp_included

========== end of global.hpp ==========

========== global.cpp ==========

#include "global.hpp"

// グローバル変数の定義(実体)
extern HMODULE g_moduleHandle = NULL;
extern volatile long g_serverLockCount = 0;

// グローバル定数の定義(実体)

// {755525B6-51FB-490b-A21B-91F7208C9429}
extern const GUID CLSID_HardLinkIconID = {
        0x755525b6, 0x51fb, 0x490b,
        { 0xa2, 0x1b, 0x91, 0xf7, 0x20, 0x8c, 0x94, 0x29 }
};

// {88A49CB3-675A-4093-9C7C-66336E30A760}
extern const GUID CLSID_MountPointIconID = {
        0x88a49cb3, 0x675a, 0x4093,
        { 0x9c, 0x7c, 0x66, 0x33, 0x6e, 0x30, 0xa7, 0x60 }
};

// {7B0F3F52-0D6E-4570-A397-E69EC97D241B}
extern const GUID CLSID_FolderLinkIconID = {
        0x7b0f3f52, 0xd6e, 0x4570,
        { 0xa3, 0x97, 0xe6, 0x9e, 0xc9, 0x7d, 0x24, 0x1b }
};

========== end of global.cpp ==========

これで、DllGetClassObject の実装は完了となる。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.