Version 3.3
ダイアログができるまで
『今日もクラスの話?』
「そう。もうちょっとだけ、全体像を見ておこうかなと思って。まず、なん
だかんだ言っても、クラスが〈型のひとつ〉、つまり変数を作るためのもの
ってことは変わりありません、ってのが Ver 3.1( No.26 )での話だった
よね」
『そーそー、あのときちょっとビックリしちゃった。なんかその辺もよく分
かんないのよね』
「そこで、今回は〈ダイアログができるまで〉と題してその流れを見ていき
ましょう」
『おー』
「さて、まず Calc.cpp を開いてみて」
『……どーやって開くんだっけ』
「そいや逆に考えたことってないかな。 CCalcApp の定義部が入ってるファ
イルだから」
『ってことは CCalcApp のメンバ関数見ればいいんだよね。【ClassView】
で CCalcApp::CCalcApp() でいーや』
「ちなみにこういう〈プロジェクト名〉のファイルには、 CCalcApp みたい
なCWinApp から継承されたクラス、つまり〈アプリの情報を管理するクラス〉
が入ってるから」
『プロジェクト作るときにそう勝手にさせられちゃうってことね』
「変えることはできるんだけどね。ま、それはおいといて、Calc.cpp のま
んなかあたりにこういう行があるでしょ」
////////////////////////////////////////////////////////////////////
// 唯一の CCalcApp オブジェクト
CCalcApp theApp;
『これ、あの〈関数の中にない変数〉よね』
「こういう〈関数の中にない変数〉変数を〈グローバル変数〉って言います。
ホントは作っちゃいけないんだけどね、グローバル変数は」
『ええっ? そんなのを天下のVCがしちゃってるの!?』
「MFCには古い部分もかなりあるからしょうがないかな。で、グローバル
変数は、アプリが実行されたときに作られて、アプリが終了したときになく
なります」
『死なばもろともって感じ〜』
「で、theApp がどういう意味のものか判る?」
『んー。えっと、 CCalcApp クラスの、変数ってことよね。つまり、アプリ
が実行されたら、CCalcApp 型の変数、 theApp ができるってことね』
「そういうこと。さて、CCalcApp に目を向けてみましょう。 CCalcApp に
はいろんなメンバ関数があります」
『んで、継承してる CWinApp とかのメンバ関数もあるんでしょ?』
「そのとおり。しかーし!」
『しかぁし?』
「どんなにメンバ関数があっても、クラス型の変数がなければ機能しませ
ん!」
『?』
「つまり……」
////////////////////////////////////////////////////////////////////
// 唯一の CCalcApp オブジェクト
// CCalcApp theApp;
「ってコメントアウトしちゃってみて」
『はーい。// ってして、ビルド、実行……あ、エラー』
「つまりこの theApp が存在しなければ、 CCalcApp は単なる飾り物、なん
の役にもたたないってこと」
『うーん……』
「逆に言うと、 theApp が作られない限り、 CCalcApp なんてクラスは存在
しない! って考えた方がいいかもね」
『存在しない?』
「想像してみて。アプリを実行する前、そこにはなんのクラスも存在してま
せんでした」
『うん、存在してない、真っ暗って感じ』
「アプリを実行すると、CCalcApp theApp; のプログラムが CCalcApp 型の
変数を作ります。するととたんに CCalcApp のクラスやそのメンバ関数が
ばーんと表れたのです!!」
『ばーんと表れた!!』
「そうすると、 CCalcApp のメンバ関数が機能するようになります。まずこ
こまでが一区切り」
『CCalcApp 型の変数を作ると、 CCalcApp のメンバ関数が使えるようにな
る、ね』
「さて、ここで〈イベント〉を思い出してみて」
『何かが起きたってことで、継ながってるメンバ関数が呼び出されるんだよ
ね。でもアプリができたってばかりでイベントなんて起きるの?』
「〈アプリができた〉ってイベントは?」
『あ』
「アプリができると〈アプリができるぞ!〉っていうイベントが発生して、
それに関連づけられたメンバ関数 CCalcApp::InitInstance() が呼び出され
ます」
『あ、これがそのメンバ関数なんだ』
「こういう重要なイベント用メンバ関数も、プロジェクトを作るときに一緒
に作ってくれるわけだね」
『至れり尽くせりだね。……でも勝手に作ってくれちゃったから、解りにく
いのかも』
「それはかなり言われてることだね、MFCの欠点として」
『へー』
「それはあとに置いといて、さてここまでを振り返ると?」
『まず、アプリが実行されるとグローバル変数ってゆーのとして CCalcApp
型の変数が作られる、そうすると CCalcApp のクラス、そしてそのメンバ関
数も機能するようになる!』
「うんうん」
『で、機能するようになると、イベントが送られてきても対応できる、そこ
で〈アプリができた〉ってイベントに対応した CCalcApp::InitInstance()
が呼び出される!』
「そういうこと。逆に言えば、CCalcApp 型の変数が作られなきゃ、どんな
ことがあっても CCalcApp::InitInstance() は呼ばれないってことだから」
『つまり〈 CCalcApp::InitInstance() がないから呼びようがない〉ってこ
とね』
「で、ここからは前に一度やったけど憶えてる?」
『はて』
「CCalcApp::InitInstance() の中を見ていくと……」
『あ!』
CCalcDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
『そうそう、ここで CCalcDlg 型の変数を作って、その DoModal() ってメ
ンバ関数を呼びだして、ダイアログが作られるんだよね』
「クラス型の変数をまず作る、ってところまでは CCalcApp と一緒でしょ」
『そういえばそうねー、ってことはつまり、このときまでは CCalcDlg が存
在しない、って考えちゃっていいってこと?』
「まぁダイアログだから CCalcDlg::DoModal() しない限りイベントもなに
も起きようがないけど、基本的にはそういうこと」
『ふ〜ん。そういえばこのあとってどうなるの?』
「まず、ダイアログが閉じるまで、さっきの」
int nResponse = dlg.DoModal();
「から動かないから」
『ここで止まっちゃうのね』
「で、ボタンが押されたとかのイベントが起きたら CCalcDlg のメンバ関数
が対応する」
『止まってるのに?』
「つまりイベントの対応をしてるから、ここで止まっちゃってるわけ」
『なるほど』
「で、【OK】ボタンを押したときに、デフォルトのメンバ関数が呼ばれて、
自動的にダイアログが閉じます」
『そのメンバ関数ってどこにあるの?』
「 CDialog の中。こういうのも、継承してるクラスの機能を使わせてもら
ってるって点かな」
『こういうのもMFCのお世話になってるのね』
「ダイアログが閉じるとさっきの行に戻って、 CCalcApp::InitInstance()
から抜けます」
『うんうん』
「終わり」
『へ?』
「つまり、CCalcApp::InitInstance() メンバ関数から抜けたときにアプリ
が終了するってこと」
『そんなにあっさりしてるもんなの?』
「それが重要。アプリができてからなくなるまで、十分追っていけるで
しょ?」
『CCalcApp の変数ができて CCalcApp::InitInstance() が呼び出されて、
その中で CCalcDlg の変数ができて CCalcDlg::DoModal() が呼び出されて
ダイアログが作られる、閉じたら CCalcDlg::DoModal() から抜けて、さら
に CCalcApp::InitInstance() からも抜けてアプリ終了。かなり単純よね』
「ま、ホントはMFCの奥の方でかなりがんばってるから、このくらい簡単
にできるんだけどね」
『こういうのもMFCに頼ってるのね……さっきも言ったけどさ、至れり尽
くせりなんだけど、なんていうか……水希ちゃんに教えてもらわなきゃ、こ
の単純さって分かんなかったかも』
「そうなんだよね、MFCのクセってとこかな」
『そうそう、押しつけられてるっていうか』
「でもね、この押しつけ、つまり〈MFCのルール〉に慣れとかないとね」
『ルール?』
「そう、これが大事っていうか……MFCでイベントを扱う時って、こうい
う方法でしか使えない、他の方法だと使いづらいんだわ」
『つまり CCalcApp を作って、継承して、とかっていうのは、MFC独特の
ルールってことなんだ』
「そう。APIだけで作るときには、かなり自由に、自分の好きなようにプ
ログラムを作れるんだけど」
『むっちゃ面倒だよね、この前の見ると』
「MFCを使ってプログラムを作れば、そのルールに従ったプログラムを作
る必要がある」
『でも楽〜』
「まずVCでプログラミングするときには、このMFCのルール、ってもの
に慣れることが大事」
『でもそれって結構特殊なんじゃない?』
「甘いね、火美ちゃん」
『な、なによ』
「この世にはあまたのライブラリがあります。たとえばウィンドウ構築用ラ
イブラリでも、ウィンドウズ用に MFC や ATL や KTL 、Linux 用にx-window
や Motif や Qt や GTK+、そのほかMAC用とか、いーっぱいあります」
『げー』
「で、それぞれに〈ルール〉があって、それに乗っ取ってプログラムを組ま
なきゃいけないわけだ」
『それが、楽をするための代償ってことなのね〜』
「もしVCのエキスパートになるんならMFCを使い込む必要があるし、そ
うじゃなくC++言語のエキスパートになるんなら、いろんなライブラリを
使いこなせなきゃいけないんだからMFCくらい使えなきゃね」
『なんか道険しいねー』
「火美ちゃんには〈C++のエキスパート〉をとりあえず目指してもらうか
ら」
『げ、勝手に決めないでよ!』
「とりあえずだって。C++をマスターしておけば、特定のライブラリのエ
キスパートになるのは楽だから」
『あ、そーゆーことね』
「話を戻すけど、さっき言ったいろんなライブラリには、それぞれルールが
あります」
『継承して使え、みたいな?』
「そうそう。APIにもルールはあるしね。ウィンドウを作ったりするくら
い複雑なライブラリだと、下手な使い方されるとまずいんだわ」
『そのために厳しいルールがあるってわけね。でもさ、そんなルールなくっ
たって、気を付けてればいいんじゃない?』
「……火美ちゃん、もう忘れたね?」
『はっ!』
「昔々、とある会社で大事故が起きました。ある薬品を、間違ったところに
入れてしまったのです。その結果……ああああ」
『ああああ……』
「もしこれが、どうやっても〈間違って入れられない〉ような仕組みだった
ら、事故は起きなかった、そう思わない?」
『Ver 2.7( No.18 ) で言ってたことねー、プログラマーも普通の人。不
注意があってもいいようにする、ってことが大事、ね?』
「そういうこと。だからルールが大事」
『継承せずには使えない、が大事……』
「火美ちゃんがこれからどんなプログラム作ってくか分かんないけど、ある
程度の規模のプログラムを作るんだったら、ルールに縛られることに慣れる
ことがまず必要かな」
/*
Preview Next Story!
*/
「型にはめられるのがイヤっていう人には、こういうのは辛いかもね」
『うん、いやー』
「んでもこういうのにも慣れないとね」
『でもあたし、自由な方がいいな〜』
「というわけで次回」
< Version 3.4 ウィンドウとウィンドウハンドル >
『につづく!!』
「これからどんどん縛ってくから」
『あ、あたし縛られるの慣れてませーん』
「逆は慣れてるでしょ」
『そーよあたしはそっちの方がってなに言わすんじゃい!』