1998.6.3

第二回
怪しげなDECLAREマクロの秘密
AppWizardの作ってくれたHファイルにはなにやら怪しげな マクロが挿入されていますね〜。DECLAREなんたらとか。 CPPファイルにもIMPLEMENTなんたらが見えます。 コレって何でしょうか。 まさかクラスの権利譲渡の契約文書では? なんて思うと夜も眠れません(僕だけ)。
今回はちょっと長いし、つまらないし、間違いだらけかも(汗)。
MFCの知らないクラスをnewしたい!
MFCは私たちの知らないところでいろいろな クラスをnewしているはずです。 そして我らプーが勝手に 派生して作ったクラスも new したいはずなんです。 だけどMFCはそのクラスの名前さえ知らないから絶対 new できない!・・・・ところが。
思いも寄らない簡単な方法
void* CreateObject()
{
    return new MyPuClass;
}
という関数へのポインタを渡したらいいんですよ。 目から鱗。あ〜簡単。さっそく実際のコードに行きましょう。
世界でもっとも簡単な基底クラス
class CObject
{

};

typedef CObject* (*PFNCREATEOBJECT)();
typedefのところが難しそうですけど つまり、戻り値がCObject*で引数がない関数へのポインタ をPFNCREATEOBJECTと言い換えたということです。
早速派生。
class CMainFrame : public CObject
{
public:
    static CObject* CreateObject();
};

CObject* CMainFrame::CreateObject()
{
    return new CMainFrame;
}

staticというは、詰まるところグローバルということ(らしい)です。 ちなみに、グローバルなんでCALLBACK関数もstaticならメンバにできるんですよこれが。 いや〜驚いた(僕だけ?)。あんまり意味無いけど(汗)。
MFCがやりそうなこと
void DoSomething(PFNCREATEOBJECT pfnCreateObject)
{
    //関数を実際に呼び出す
    CObject* pObject = (*pfnCreateObject)();

    //pObjectを使って何かやる
    //・・・

    delete pObject;
}

void main()
{
    DoSomething(&CMainFrame::CreateObject);
}
これはその関数へのポインタを使ってその関数を実際に 呼び出しています。こうやってMFCは名前も知らないクラスの オブジェクトを生成しているに違いない(たぶん)。
マクロを作ろう。
とここまで見てきたわけですが、CreateObjectメンバ関数なんて、 たいていどのクラスでも似たようなもの になるはずです。違うのはクラス名だけだし。 というわけでマクロにしましょ。
#define DECLARE_DYNCREATE(class_name) \
    static CObject* CreateObject();

#define IMPLEMENT_DYNCREATE(class_name) \
    CObject* class_name::CreateObject() \
    { return new class_name; }

#define RUNTIME_CLASS(class_name) \
    &class_name::CreateObject  
簡単でしょう?(これあってるのかな・・(汗))
先ほどの派生クラスをマクロを使って
class CMainFrame : public CObject
{
public:
    DECLARE_DYNCREATE(CMainFrame)
//  static CObject* CreateObject();
};

IMPLEMENT_DYNCREATE(CMainFrame)
//CObject* CMainFrame::CreateObject()
//{
//	return new CMainFrame;
//}

void main()
{
    DoSomething(RUNTIME_CLASS(CMainFrame));
//  DoSomething(&CMainFrame::CreateObject);
}
コメント部が不要になった部分です。すごく短くなりました。
実は。
これらはInside VC++って本の中身そのままでした(汗)。 さらにわかりやすく(にくく)してみました(汗)。 ところで、CreateObject関数へのポインタ以外にも渡したい物があるのは 僕だけじゃないはず(汗)。他にもクラスの名前とかも渡したいなら 構造体をメンバにしたらいいのかな?(これは宿題にしましょ(汗)。)


  ひとつ戻る

トップページへ