コール関数リストの作り方

[戻る]
こーひ 2002/05/11(土) 10:24:37
MFC でウィンドウ内に複数の子ウィンドウを貼り付け、それらの子ウィンドウ内で
さらに複数の子ウィンドウ(孫ウィンドウ)を貼り付けるといった構成のアプリを
作っています。

そこで、ある孫ウィンドウ上のスライダで値を変更すると、いとこにあたる孫ウィ
ンドウのエディットボックスの値が変わるという仕組みをどのように作ったらよい
か分からずに困っています。

ドキュメントクラスにコール関数リストみたいなものを作ったらどうかとも思って
みて、vector<void *> で挑戦したのですが、うまくいきませんでした。

「いとこ」にあたるウィンドウの関数をコールする方法、あるいは
コール関数リストの作り方を教えてもらえないでしょうか。

私が考えたプログラム
-----
ドキュメントクラスにおいて
std::vector<void *> callfunc;
void Call() 
{
  for (int i = 0; i < callfunc.size(); i++)
     (*this)[i]();  // <- ここでコンパイルエラーがでます
     // error C2064: 関数ポインタとして評価されない式を使って、
     // 関数を呼び出そうとしました。
}

ある孫ウィンドウにおいて、
pDoc->callfunc.push_back(<関数名>);

別の孫ウィンドウにおいて、
pDoc->Call();
-----

YuO [E-Mail] 2002/05/11(土) 15:31:17
根本的な間違いがありますよ。

> (*this)[i]();  // <- ここでコンパイルエラーがでます

thisポインタは何を指していますか?
(*this)[i],つまりthis->operator[](i)は正しい呼び出しで,
関数ポインタまたは関数呼び出し演算子を実装したクラスのオブジェクトを返しますか?


あと,void *ではなく,実際の型にしないと呼び出しが面倒です。

dairygoods 2002/05/13(月) 10:07:55
> 「いとこ」にあたるウィンドウの関数をコールする方法

ビュークラスにエディットボックスのポインタを
保持しておけばよいのでは?

こーひ 2002/05/13(月) 13:28:06
[[解決]]
YuO さん、dairygoods さん、ご助言ありがとうございます。

ご助言を基にいろいろ考えて、下記の方法で解決しました。
いまのところ、うまくいっているようです。
ありがとうございました。

-----
// ◆CallFuncClass と、そのリストクラスを作る
class CallFunc {
    CallFuncClass() {};
    ~CallFuncClass() {};
    virtual void CallFunc() = 0;
};
class CallFuncList: public std::vector<CallFunc *> {
    CallFuncList() {};
    ~CallFuncList() {};
    void Call()
    {
        for (int i = 0; i < size(); i++)
            (*this)[i]->CallFunc();
    };
};

// ◆ドキュメントクラスでリストを保有
class XXDoc: public CDocument, public CallFuncClass {

    CallFuncList cfl;
};

// ◆呼び出される側のクラス
class XXCalledClass: public CallFunc {
    virtual BOO OnInitDialog()
    {
        GetDocument()->cfl.push_back(this);
    };
    void CallFunc()
    {
         // 処理したい内容
    };
};

// ◆呼び出し側
void CallRoutine()
{
    GetDocument()->cfl.Call();
}
-----

こーひ 2002/05/14(火) 00:58:24
こーひです。
解決したと書いたコードが間違っていましたので、修正します。

正しくは以下です。
-----
// ◆CallFuncClass と、そのリストクラスを作る
class CallFuncClass {
    CallFuncClass() {};
    ~CallFuncClass() {};
    virtual void CallFunc() = 0;
};
class CallFuncList: public std::vector<CallFuncClass *> {
    CallFuncList() {};
    ~CallFuncList() {};
    void Call()
    {
        for (int i = 0; i < size(); i++)
            (*this)[i]->CallFunc();
    };
};

// ◆ドキュメントクラスでリストを保有
class XXDoc: public CDocument {

    CallFuncList cfl;
};

// ◆呼び出される側のクラス
class XXCalledClass: public CallFuncClass {
    virtual BOO OnInitDialog()
    {
        GetDocument()->cfl.push_back(this);
    };
    void CallFunc()
    {
         // 処理したい内容
    };
};

// ◆呼び出し側
void CallRoutine()
{
    GetDocument()->cfl.Call();
}
-----

YuO [E-Mail] 2002/05/14(火) 08:36:24
vectorを継承させるのではなく,

// VC++ (6.0およびそれ以前)の制限。
// 標準には戻り値がvoidでも適合
>     virtual void CallFunc() = 0;
    virutal int CallFunc() = 0;

// ラッパクラスは利用しない
> class XXDoc: public CDocument {
>     CallFuncList cfl;
> };
class XXDoc : public CDocument {
    typedef std::vector<CallFuncClass *> CallFuncList;
    CallFuncList cfl;
};

// 呼び出しはfor_eachとmem_funで処理
> void CallRoutine()
> {
>     GetDocument()->cfl.Call();
> }
void CallRoutine (void)
{
    CallFuncList & cfl = GetDocument()->cfl;
    std::for_each(cfl.begin(), cfl.end(), std::mem_fun(&CalFuncClass::CallFunc));
}
このようにすれば,CallFuncListクラスは不要です。もともと,
> (*this)[i]->CallFunc();
これは,
cfl[i]->CallFunc();
と書けていたわけですから。

古いスレッドには追加発言できません。