Version 17.05
CWnd クラスの継承関係
「前回は protected とかのアクセス修飾子のまとめをしました」
『とりあえずはこれまで通りで、派生クラスから使いたいときに protected
ってとこ?』
「そんな感じかな。今回は、派生クラスでメンバ変数やメンバ関数を受け継
ぐことができる、っていう部分のまとめとして CWnd クラスについて見てい
きます」
『あれ、 CWnd クラスって MFC の?』
「そう。まず MSDN の CWnd クラスのページを開いて」
『ほい開いたよ』
「次に、一番下にこう書いてあると思うんだけど」
#include <afxwin.h>
クラス メンバ | 基本クラス | 階層図 ←←←←←ここ
サンプル MFC サンプル BINDENRL | MFC サンプル EXTBIND | ...
参 照 CFrameWnd、CView
「この【階層図】のところをクリックして」
『ほい。あ、なんか図が出てきた』
「これは、 MFC の〈基本クラスと派生クラスの関係〉を示した図です」
『つまりどう継承してるか、ってこと?』
「そういうこと。左上が基本クラス、右下が派生クラスって読めばいいか
な」
『もしかして、 MFC のクラスって全部この中に書かれてる?』
「うん、全部書かれてるよ。つまり、 MFC のクラスは、それぞれが単体で
存在しているんじゃなくて、何らかの形で継承してるってこと」
『へー、そういうの意識してこなかったけど、こんなとこで継承とか使って
るんだ』
「その中でも、 CWnd クラスを中心にした継承関係を見ていこうか」
┌─────────┐
│CWnd クラス │
└─────────┘
△
├──────────┬─────────┐
│ │ │
┌────┴────┐┌────┴───┐┌────┴────┐
│CDialog クラス ││CView クラス ││CButton クラス │
└─────────┘└────────┘└─────────┘
△ △
│ │
│ │
┌────┴────┐┌────┴───┐
│各ダイアログクラス││各ビュークラス │
└─────────┘└────────┘
「とりあえずはこんなところかな」
『少な!』
「まぁ全部書くと大変だからね……」
『それに、〈各ダイアログクラス〉とかは何? MFC のクラスじゃないよ
ね』
「これはあとで説明するから。まずは……」
・CWnd クラス
『これは何度も使ってるものね』
「そう、ウィンドウを使うためのクラス。でもこのクラス単体で使ったこと
はほとんどないと思うよ」
『え……あれ、そういえばそうかも? なんでだろう』
「それは、派生クラスを使うことがほとんどだから。でも派生クラスで、
基本クラスのこの CWnd クラスのメンバ関数を使うことが多いから」
『使っていた気になってた?』
「っていうことかも。その例として……」
・CButton クラス
『ボタンを使う時のクラス! Version 5.25 ( No.090 ) とかで使ったね』
「そう、ダイアログに貼り付けるボタン、エディットボックス、
ドロップダウンリストといったコントロールはすべてウィンドウ、」
『だから CWnd クラスの派生クラスなの?』
「そういうこと。 CWnd クラスの派生クラスにすることで、 CWnd クラスの
持つ〈ウィンドウを操作する機能〉をそのまま受け継ぐんです。たとえば
Version 5.26 ( No.091 ) では CWnd クラスの SetWindowText() メンバ関数
を使用しています」
// いつものメンバ関数。
void CFileTestDlg::OnBtnShow()
{
CButton cShowBtn;
cShowBtn.Attach
( ::GetDlgItem( GetSafeHwnd(), IDC_BTN_SHOW ) );
cShowBtn.SetWindowText( "あいうえお" );
cShowBtn.Detach();
return;
// あとは取っておきましょう。
「この以下の箇所がそう」
cShowBtn.SetWindowText( "あいうえお" );
『そか、 SetWindowText() って CWnd クラスのメンバ関数だね』
「このようにして、 CButton クラスの変数を通して、基本クラスの
CWnd クラスのメンバ関数を呼び出しているわけです」
『つまり、こうして基本クラスのメンバ関数を派生クラスで使える、ってい
う例をなんども見てきた、と』
「そういうこと。本当に何度となく、ね」
『むむむ』
「たとえばダイアログアプリケーション」
『んー、それって Version 4.01 ( No.051 ) とかで教わったののことだよ
ね』
「そう、ダイアログを表示するだけのプロジェクト。そうして作成した
プロジェクトにはダイアログクラスがあったでしょ」
『その Version 4.01 ( No.051 ) の時だと CTestApp01Dlg クラスのこと
だよね。……あ! それってもしかして、それが』
┌─────────┐
│CWnd クラス │
└─────────┘
△
│
│
┌────┴────┐
│CDialog クラス │
└─────────┘
△
│
│
┌────┴────┐
│各ダイアログクラス│←これ
└─────────┘
『のこと!?』
「そういうこと! ダイアログアプリケーションを作成すると、 AppWizard
が CDialog クラスの派生クラスを作成します。たとえば以下のように」
// TestApp01Dlg.h : ヘッダー ファイル
//
// 略
////////////////////////////////////////////////////////////////////
// CTestApp01Dlg ダイアログ
class CTestApp01Dlg : public CDialog
{
// 略
};
『はー、そういえばそうだね。なんか今まであまり意識してこなかったけど』
「こうして作られたダイアログクラスは CDialog クラスの派生クラスです。
かつ、 CWnd クラスの派生クラスでもあるんです」
『 CDialog クラスが CWnd クラスから継承しているから?』
「そういうこと。こうして連続して継承していけば、ダイアログクラスは
CWnd クラスと CDialog クラスの両方のメンバを受け継いだことになる
わけです」
『ってことは、こうして作られたダイアログクラスから、 CWnd クラスの
メンバが使えるってこと、ってゆーか使ってるよね、さっきの
SetWindowText() とか使ったことあるもん』
「 Version 3.2 ( No.027 ) とかで使ってるね」
void CCalcDlg::OnBEqual()
{
SetWindowText( "あいうえお" );
}
『使ってた……なんかすごく何気なく使ってたけど、ちゃんと継承って機能
でメンバ関数を引き継いでいたから使えたんだ……』
「同じく、 Version 9.01 ( No.162 ) で作成した SDI アプリケーションの
場合には、 AppWizard が CView クラスの派生クラスとしてビュークラスを
作成しました」
┌─────────┐
│CWnd クラス │
└─────────┘
△
│
│
┌────┴────┐
│CView クラス │
└─────────┘
△
│
│
┌────┴────┐
│各ビュークラス │
└─────────┘
「たとえば Version 9.05 ( No.166 ) の、右クリックメニューを表示する
プログラムでは GetCursorPos() メンバ関数とかを呼び出しているけど、こ
れも」
『 CWnd クラスのメンバ関数ってわけねー』
「で、重要なのは、もし継承って機能がなかったら、これどうなると思
う?」
『継承がなかったら……んー、ひとつひとつのクラスにウィンドウを操作す
る機能が必要になる……そか、 CDialog クラスとか自分が作ったクラスに
SetWindowText() メンバ関数を追加したりしなきゃいけなくなる!』
「そういうこと。継承を使うことで、基本クラスにメンバ関数を作っておけ
ば、それを継承するだけで多くの派生クラスで利用することができる、とい
うわけです」
『その楽をするために継承を使う、ってわけね』
「う”、そういうわけでもないんだけど……」
/*
Preview Next Story!
*/
『違うの? 違うの??』
「うーん、……まぁそれは置いといて」
『置いとくんかい!』
「次回は目一杯複雑な話です」
『なんですと!?』
「というわけで次回」
< Version 17.06 継承と代入 >
『につづく!』
「継承と代入が絡むととっても大変なことになるんです」
『大変なことってなにー!?』