ダイアログクラスの継承

解決


阪神  2005-09-16 18:09:44  No: 59070  IP: 192.*.*.*

教えてください。

下記のように、
CDlgAクラスのOnYes()を
CDlgAクラスを継承したCDlgBクラスで
オーバーライドしたいとおもっているのですが
うまく出来ません。

何か気付く点がありましたらご指摘願います。

class CDlgA : public CDialog
{
    virtual afx_msg void OnYes();//適用ボタン押下時処理(自動生成コード)
                                  //「virtual」は後付け
}

class CDlgB  : public CDlgA
{
    void OnYes();    //CDlgAのOnYes()をオーバーライドしているつもり
};

編集 削除
επιστημη  2005-09-16 21:14:18  No: 59071  IP: 192.*.*.*

メッセージマップでハンドルされるメソッドはvirtualになれません。

class CDlgA : public CDialog
{
    afx_msg void OnYes();//適用ボタン押下時処理(自動生成コード)
    virtual void do_OnYes();
}

void CDlgA::OnYes() { do_OnYes(); }

class CDlgB    : public CDlgA
{
    virtual void do_OnYes();
};

…これでいかがでしょうか(自信なし)

編集 削除
愚暗  2005-09-18 14:31:28  No: 59072  IP: 192.*.*.*

メッセージマップマクロを追加するのを忘れている、
というオチではないですよね?

編集 削除
てつや  2005-09-19 09:53:08  No: 59073  IP: 192.*.*.*

windowsから送られてくるメッセージは引数にHWNDがあるだけで、
MFCのクラスのどのインスタンスなのかはわかりません。
だからCHandleMapというクラスを使って、HWNDがどのインスタンスのメンバ
なのかを特定します。
この時、必ず派生先のインスタンスを特定してしまうので、オーバーライド
できないのです。
(必ずCDlgBのハンドラがよばれ、CDlgAのハンドラは無視される。)

派生元の関数を呼ぶのであれば、CDlgAの仮想関数をCDlgB::OnYes()の中で
呼び出し、そしてCDlgBに仮想関数の実装をする...
ややこしいので、やらないほうがいいと思います。

編集 削除
阪神  2005-09-20 09:29:30  No: 59074  IP: 192.*.*.*

回答ありがとうございます。

>class CDlgA : public CDialog
>{
>    afx_msg void OnYes();//適用ボタン押下時処理(自動生成コード)
>    virtual void do_OnYes();
>}
>
>void CDlgA::OnYes() { do_OnYes(); }
>
>class CDlgB    : public CDlgA
>{
>    virtual void do_OnYes();
>};

>…これでいかがでしょうか(自信なし)

試してみました。
うまく動作しました。
多少コードが煩わしくなるようですが、
個人的には、これでいいのかと思いますが、
このような方法は一般的なのでしょうか?

同じようなダイアログを3つ程度つくることになる場合、
1つのリソースを共有させたいのですが。
現状、リソースに対してクラスを1つ作り、
OnYes()の処理の中で、switch文で3つの処理を分岐
しているのですがコードが煩わしくなるので避けたいのです。
OnYes()の処理だけならともかく、OnInitDialog()関数や、
ダイアログに配置したボタンの処理等、全てswitch文で分岐
しています。

>メッセージマップマクロを追加するのを忘れている、
>というオチではないですよね?

すみません、メッセージマップマクロとは何でしょうか?

>派生元の関数を呼ぶのであれば、CDlgAの仮想関数をCDlgB::OnYes()の中で
>呼び出し、そしてCDlgBに仮想関数の実装をする...

επιστημηさんと同じ内容の意でしょうか?
理解力がなくてもうしわけないです。

編集 削除
επιστημη  2005-09-20 11:43:10  No: 59075  IP: 192.*.*.*

> このような方法は一般的なのでしょうか?

MFCの流儀ではどうか知らんが、オブジェクト指向屋は'ふつー'にやらかします。
デザイン・パターンでいうところの"Template Method"ってやつ。

> すみません、メッセージマップマクロとは何でしょうか?

Windows-Message(ここではYesボタン押下)とそのハンドラ(ここではOnYes)とを
結びつけるマクロ。
このマクロで両者を組にした表が内部に作られ、Messageを受理したときにこの表を引いて、対応するメソッドに火をつけています。
だからこのマクロがちゃんと書かれていないとヘンなとこに飛んでいきます。

編集 削除
RAPT  2005-09-20 23:38:17  No: 59076  IP: 192.*.*.*

switch文で書くのが嫌なら普通にクラスを3つ作成すれば良いだけでは?

編集 削除
阪神  2005-09-21 09:02:50  No: 59077  IP: 192.*.*.*

回答ありがとうございます。

>switch文で書くのが嫌なら普通にクラスを3つ作成すれば良いだけでは?

1つのダイアログに複数のクラスを関連付けるのは
可能なのでしょうか?

編集 削除
isshi  2005-09-21 10:42:48  No: 59078  IP: 192.*.*.*

>1つのダイアログに複数のクラスを関連付けるのは
>可能なのでしょうか?
可能です。
VC7.1ならクラスウィザードで普通にできます。
VC6だとウィザードではだめなので(多分)、1つはウィザードで作り、
その他は1つ目を真似て手書きすればよいです。
ただ、手書きしたクラスについては、メンバ関数の自動追加などの便利な機能は
使えませんが。

編集 削除
阪神  2005-09-21 11:14:25  No: 59079  IP: 192.*.*.*

回答ありがとうございます。

>可能です。
>VC7.1ならクラスウィザードで普通にできます。
>VC6だとウィザードではだめなので(多分)、1つはウィザードで作り、
>その他は1つ目を真似て手書きすればよいです。
>ただ、手書きしたクラスについては、メンバ関数の自動追加などの便利な機能は
>使えませんが。

了解しました。

ただクラスを3つ作る方法だと、
例えば、ダイアログに配置するエディットボックス等のコントロール
の追加時に、そのメンバ変数を3つのクラス共追加しないといけない
ので面倒のような気がしますがいかがでしょうか?

編集 削除
RAPT  2005-09-21 11:22:27  No: 59080  IP: 192.*.*.*

そんなん、どっちが良いかは、あなたが選択すればよい。

何なら、共通部分を抜き出した基本クラスを作っておいて、
派生クラスで必要な部分のみオーバーライドしてやれば良いのでは?

編集 削除
阪神  2005-09-22 13:01:56  No: 59081  IP: 192.*.*.*

回答ありがとうございます。

>そんなん、どっちが良いかは、あなたが選択すればよい。

>何なら、共通部分を抜き出した基本クラスを作っておいて、
>派生クラスで必要な部分のみオーバーライドしてやれば良いのでは?

そうですね。失礼しました。
ただ、一般的な方法が知りたかったのです。

3つのクラスを作成する方法、
共通部分を抜き出した基本クラスを作りそこから派生させる方法
とで、場合によって使い分けることにします。

編集 削除