Version 3.9
ラッパークラス!
「さっそく前回を振り返ってみると」
『CWnd の中には m_hWnd って変数、メンバ変数があって、CWndのメンバ関
数を呼び出すと、この m_hWnd をAPIの方に渡してる、って話だったよね』
「そうそう。今回はこの部分をもっと突き詰めて考えてみます」
『おー』
「さて、まず最初に CCalcApp::InitInstance() の定義部を表示してみて」
『……?』
「CCalcApp は?」
『えっと、確かアプリの本体を管理するクラスとかなんとか……Calc.h と
Calc.cpp の中にあるんだよね』
「CCalcApp::InitInstance() は?」
『あ、これは憶えてるよ。たしか〈アプリができるぞ!!〉って時に呼ばれ
るメンバ関数だよね』
「で、定義は〈関数の本体〉のことだから……」
『ってことは Calc.cpp の中にあるから、これを【FileView】で開いてっと
……うん、表示したよ』
「じゃ、こんなふうに書き加えて」
BOOL CCalcApp::InitInstance()
{
// ここから書き加えてください。
HICON hIcon;
hIcon = ::LoadIcon( m_hInstance
, MAKEINTRESOURCE( IDI_ICON1 ) );
TRACE( "%X\n", hIcon );
hIcon = LoadIcon( IDI_ICON1 );
TRACE( "%X\n", hIcon );
// ここまで書き加えてください。
// あとはそのまま。
AfxEnableControlContainer();
// 以下略。
『うわー、なんかむつかしそー』
「最初からひとつずつ考えてみれば大丈夫。まず最初は?」
『hIcon って変数作ってる。HICON 型だからアイコンハンドル入れるんだよ
ね』
「そうそう。次も前に見たのでしょ」
『あ、LoadIcon() ってAPIを呼んで、アイコンのハンドルをもらうんだ
よね。……あれ? m_hInstance って……』
「これは初見のはず。これは CWinApp のメンバ変数で、インスタンスハン
ドルを格納してるもの」
『??』
「まず CWinApp は?」
『たしか、CCalcApp はその CWinApp ってクラスから継承してるんだよね。
だから CCalcApp は CWinApp の機能をそのまま使えるんだよね』
「そうそう。インスタンスハンドルは?」
『アプリのハンドル。でもさ、この前は AfxGetInstanceHandle() って関数
呼んでたよね』
「AfxGetInstanceHandle() は m_hInstance が持ってるのと同じハンドルを
返してるから、基本的には同じ事だね」
『ふーん。で、メンバ変数ってことは、m_hWnd と同じ感じってことね〜。
ってことはやっぱし CWinApp 見るとそんなかにあるの?』
「そう。この前使った全文検索で検索してみると……」
(以下 MFCからの引用)
class CWinApp : public CWinThread
{
DECLARE_DYNAMIC(CWinApp)
public:
// Constructor
CWinApp(LPCTSTR lpszAppName = NULL);
// Attributes
// Startup args (do not change)
HINSTANCE m_hInstance;
(引用 ここまで)
『ほんとだー、m_hWnd のときと同じだね』
「あと、メンバ変数は m_ って付けるルールになってるから。これなら一目
瞭然でしょ」
『うん、分かりやすいかも』
「で、次は?」
『次の TRACE() は、ハンドルの出席番号ってのの表示』
「そ。次は?」
『あれ? LoadIcon() 呼んでるってことは、同じことしてるの?』
「ちょっと違うかな。よーく見てみて」
『ん……あ、これ、:: が付いてないから CWinApp のメンバ関数だ』
「そういうこと。ちなみに前に使った AfxGetApp()->LoadIcon() と同じメ
ンバ関数」
『あ、そういえば〈 AfxGetApp()-> を付けると CWinApp のメンバ関数を呼
べる〉って言ってたもんね』
「最後はさっきと同じ、ハンドルを表示するもの」
『つまり……APIのとMFCのを同時に使ってるってこと?』
「そう、比較のためにね。とりあえず実行してみて」
『ビルドして実行。あ、同じ数字が出てきた!!』
「つまり同じ機能ってこと」
『へー、これって CWnd の時と似てる……って、そういうこと?』
「そういうこと。整理すると、CWnd も CWinApp も、中にハンドルを格納す
るためのメンバ変数を持ってます」
『m_hWnd と m_hInstance ね』
「両クラスとも、APIと同じ名前のメンバ関数を持っていて、中でこのメ
ンバ変数を渡しています」
『代わりに渡してくれてるってことなのかな』
「一応ね。この2点が、MFCのクラスの基本的なとこ」
『ってことは他のクラスもハンドルを中に持ってるってこと?』
「そういうこと。ウィンドウハンドルを持ってる CWnd や CDialog は知
ってると思うけど、それ以外にもウィンドウに絵を描くための〈デバイスコ
ンテキスト〉のハンドルを持つ CDC とか、メニューのハンドルを持つ CMenu
とか」
『ってゆーか、そういうのにもハンドルがあるってことの方が驚きかも……』
「その辺はまた今度ね。で、MFCのクラスのほとんどがハンドルを持って
て、そのハンドルを渡すAPIと同名のメンバ関数を持ってる」
『それがMFCのパターンってことなのねー』
「ちなみにこういう〈元々あるライブラリを使いやすくするためのクラス〉
を〈ラッパークラス〉って言います」
『ダンスダーンス! みたいな?』
「そのラップじゃなくてー、くれらっぷとかさらんらっぷとかのラップ」
『……ハンドルって生鮮食品?』
「うーん、そーじゃなくってねー、APIやハンドルを包み込んでる、って
感じかな」
『あ、クラスの中にハンドルのメンバ変数入れて、APIと同じメンバ関数
入れて、クラスの中に全部閉じこめちゃうって感じかな』
「ラッパーだと間違えちゃうからか、MSDNじゃラップクラスって書いて
ある部分もあるみたいだね」
『どーせなら〈ナンクラス〉とか〈サンチュクラス〉にすればいーのに』
「なにそれ」
『なんでしょー、ふふふ』
「……さて!」
『あ』
「ここでここまでを振り返ってみます。まずハンドルってものについて」
『ウィンドウとかアイコンとかの出席番号! だよね』
「そうそう。このハンドルをAPIに渡すことで、そのウィンドウとかアイ
コンを操作できたわけだ」
『他のウィンドウのタイトル変えたりねー』
「つまり、この〈ハンドルとAPI〉だけでプログラムを組むと、ハンドル
を入れる変数を作って、その中にハンドルを入れて、APIに渡す、って形
になるよね」
『んー、そうなるのかな』
「たとえばさ、たいがいのアプリってファイル名がタイトルに出るでしょ」
『うん』
「この〈タイトルを変える〉ってことをするためには、自分のアプリのウィ
ンドウのハンドルを持ってなきゃいけないってことでしょ」
『それを変数として持っておくってことね』
「そうそう。で、MFCはこの部分を自動的に処理しよう! ということで、
普通の変数じゃなくて」
『メンバ変数!』
「を使ってハンドルを取っておこう、ってことにしたわけ」
『……なんかでもよく分かんないけど』
「じゃあね、イメージとしては……電話」
『でんわ?』
「電話で他の人に色々して欲しいときは、短縮でその人の番号を選んで、電
話かけて、色々言えばいいでしょ」
『あたりまえだよね』
「もしいろんな人に指示したいときは、その都度短縮リストから選ばなきゃ
いけないわけだ」
『そうなるよねー。……もしかしてそれがハンドル?』
「そ。電話番号がハンドル、短縮リストがハンドルを入れる変数、電話は
APIってとこかな」
『うーん、アイコンとかいっぱいあったら、その数だけハンドルとそれを入
れる変数があって、それをAPIに渡さなきゃいけない、ってこと?』
「そういうイメージ。これをクラスに置き換えて考えると、携帯がいっぱい
あるような感じ」
『携帯がいっぱい?』
「そ、1個の携帯にはひとつの電話番号しか入ってない、つまり人と電話機
が1対1になってるわけ」
『つまり短縮から選ぶ必要がないってことね。でも電話は選ばなきゃいけな
いでしょ?』
「もちろん。その点じゃ、それほどメリットないかな。メリットがあるのは、
カスタマイズ」
『どゆこと?』
「たとえば雑誌の編集者さんとは誌面の情報をやりとりしたいからカメラ付
きの携帯にするとか、友達とは長い時間話すから安いピッチにするとか」
『つまり携帯をそれぞれ向いたものに変えるってことよね』
「今はまだ無理だけど、偉い人用のは自動的に丁寧な言葉遣いにしてくれる
とか」
『あ、それいーかも。……でもそれって、プログラムになんか関係あんの?』
「継承」
『あ……』
「MFCに置き換えて考えてみようか。Calc プロジェクトの中には、いつ
も見るダイアログ用の CCalcDlg と、〈バージョン情報〉用の CAboutDlg
のふたつが入ってます」
『Ver 3.1( No.026 )でやったのだよね』
「このふたつのダイアログをMFCを使わずに操作するときには、HWND 型
の変数をふたつ用意します」
『それをAPIに渡して操作する、それが〈ひとつの電話機にいっぱいの短
縮ダイヤル〉ってことだよね』
「そう。MFCの場合には、ふたつのクラス型変数を用意して、その中にハ
ンドルを取っておきます」
『それが携帯を番号の数だけ用意するってことね』
「ん、ちょっと違うかな」
『え?』
「実は、ダイアログを表示するだけなら CDialog さえあればOK。つまり
継承する必要はないんだよね」
『ってことは CCalcDlg と CAboutDlg ってホントはいらないってこと?』
「そういうことになるかな。この、提供されたMFCのクラス型の変数を
使ってダイアログを作る、ってことが」
『これが〈携帯を番号の数だけ用意する〉よね』
「そういうこと。だけどこのふたつのダイアログ、違ったことをさせたいわ
けで」
『そのために〈番号ごとに違う携帯を用意する〉、それが継承ってことなの
ねー』
「電話番号っていう簡素なものを、個性的な携帯に置き換えることで意味の
あるものにする、つまり〈携帯で電話番号を包む〉」
『ラッパークラス、ってこと?』
「そう。ハンドルっていうものをクラスで包み込んで、使いやすくカスタマ
イズする、これがMFC流ってことかな」
『MFC流、ねぇ』
「そう、これが大事なんだよ」
『なんで?』
「APIはウィンドウズそのものの機能だから、変えようがないでしょ」
『そんなこと言ってたよね』
「だけどそんなに使い勝手がいいわけじゃない。そこでMFCは、MFCを
作った人は〈ラッパークラスを作って便利にしよう!〉と考えた」
『だから CWnd とかができたってこと?』
「そう。ラッパークラスを作って継承できるようにして、この継承したクラ
スでプログラムを構成できるようにしよう、っていうのがMFC流の根幹」
『……つまり、前言ってた継承の話と同じでしょ?』
「それにハンドルを加えて考える、ってこと」
『あ、そっか』
「Ver 3.3( No.028 )までに言ったように、MFC使ってプログラムを作
るってことは、MFCのクラスを継承した新しいクラスを作って、それをカ
スタマイズするってこと」
『そーすれば、MFCのクラスが持っている機能をそのまま使いつつ、拡張
できるのよねー』
「その〈MFCのクラスの機能〉こそが、ハンドルをメンバ変数として持っ
ていて、APIを変わりに呼び出してくれる、つまり」
『ラッパークラス!』
「としての機能。つまりこういう仕組みは、ハンドルを使わないでプログラ
ムを組むためにあるわけだ」
『それがMFCの親切心、ってわけね』
「ま、実際に親切かどうかはともかく、そういうこと。ここまでの話をよー
く復習して、あと CCalcDlg とかのプログラムをよーっくみて、その辺しっ
かりと理解しておいてください!」
『は〜い』
/*
Preview Next Story!
*/
『でもさ、なんか同じ事ねちっこく言ってない?』
「重要だと思うからね。まあ時間掛かり過ぎとは思うけど」
『で、計算機ってさー、いつできんの?』
「つぎ」
『へ?』
「というわけで次回」
< Version 3.10 数字をやりとりしよう! >
『につづく!!』
「もしかしたら年内に Ver 4 に行けるかも」
『またどーせ同じ事何度も何度も言って伸びるんだよきっと』
「う”、でもその方がいーでしょ?」
『う”、まぁそうかもしんないけど……』