Version 7.08
コンストラクタで初期化
「今回は〈クラス〉について少し深く見てみましょう」
『うん、クラスっていろんな機能があって、使えるけどよく分かんない感
じ』
「 C++ 言語を使う上での最初の目標は、必要最低限のことを踏まえたクラ
スをさくっと作れることかな」
『……クラスを作る?』
「そ。今は到底無理とか思うでしょ」
『っつーか絶対無理』
「でもいつかはできるようになるから。ま、そのためにはこつこつ勉強しな
いとね」
『はいはい。で、今日は?』
「今日はクラスの便利な機能について。まずはコンストラクタ」
『コンストラクタってやったよ? Ver 5.17 ( No.082 ) で』
「そう、クラスを作る時に関数を呼べるんです。それがクラス。あのとき
は」
std::istrstream cStrStrm( chAllLine, dwReadedSize );
『そうそうそんな感じ。 chAllLine って配列から数字とか取り出すのに使
うんだよね』
「そう。で、ここで大事なのは〈初期化〉ってこと」
『しょきか? それって最初の準備することだよね』
「そうそう。 std::istrstream の機能を使うためには、整数とかを取り出
すための文字配列がなきゃいけないでしょ。その準備をすることが初期化」
『つまり、コンストラクタ=初期化、なんだっけ?』
「そゆこと。クラスを使うためにはその準備、つまり初期化をしなきゃいけ
ない、その初期化をする専用のメンバ関数が、コンストラクタ」
『それを上のは呼んでるってわけね』
「でも実は、自動的にコンストラクタが呼ばれてたりするんです」
『自動的?』
「まずは、クラスじゃない例から」
void CAnimeDlg::OnBDraw()
{
HWND hWnd;
TRACE( "%X\n", hWnd );
// CCCCCCCC
}
『???』
「 hWnd って変数を作って、で、中身に何も入れないでその中身を表示した
だけ」
『そうすると CCCCCCCC ってなるの?』
「っていうか、元々そうっていうか。そうだ」
void CAnimeDlg::OnBDraw()
{
HWND hWnd;
TRACE( "%X, %X\n", hWnd, &hWnd );
// CCCCCCCC, 64F544
}
「ってやって、久々にメモリの中身見てみようか」
『なんか久しぶり。 TRACE の次の行でブレークポイント置いて、実行して
そこで止めて』
「【表示】−【デバッグ ウィンドウ】−【メモリ】でメモリウィンドウを
表示して、上の欄に 0x0064F544 って入れてリターン」
0064F544 CC CC CC CC AC FC 64 00 84 F5 64 00 9C 74 43 5F EC F7 64 00
『これがメモリの中身なんだよね』
「で、 HWND hWnd したら 0x0064F544 から4マス分確保してるわけ」
『この辺は Ver 4.02 ( No.052 ) とかでやったから分かるかなー』
「で、変数ってのはメモリの場所を取るだけだから」
『そっか、だから上の CC CC CC CC がそのまま hWnd の中に残ってるか
ら、 CCCCCCCC って出ちゃったんだ』
「そゆこと。もちろん、このままじゃ使えないし、この状態で使うとまずい
んだよね」
『そこで初期化?』
「そゆこと。たとえば」
void CAnimeDlg::OnBDraw()
{
HWND hWnd = NULL;
}
「これも初期化」
『ただ NULL 入れてるだけだけどね』
「でも、無茶苦茶な値じゃないから、 if( hWnd == NULL ) ってすれば」
『初期化されたままかどうかが分かるわけね』
「で、この初期化を代わりにしてくれるのが、コンストラクタ」
void CAnimeDlg::OnBDraw()
{
CWnd cWnd;
TRACE( "%d\n", cWnd.m_hWnd );
// 0
}
『あ、 0 になってる!』
「これは、 CWnd のコンストラクタが m_hWnd = NULL を代わりにしてくれ
てるってこと」
『でも関数呼んでるって感じじゃないね。これがさっき言ってた〈自動的に
呼ばれる〉っていうのなんだ』
「そう、この〈自動的に呼ばれるクラス〉を【デフォルトコンストラクタ】
って言います」
『でふぉるとこんすとらくた』
「そ。デフォルトっていうのは」
『最初の状態とかそういうのだよね』
「そうそう。何はともあれ必要なコンストラクタってことだね。って言って
も、これも自分でクラスを作る時には自分で用意しないといけないんだけど
ね」
『ってことは、自動的に m_hWnd = NULL ってならないんだ』
「だって、 NULL 以外の値にしたいときだってあるわけでしょ」
『そりゃそうだ』
「で、ちなみにその CWnd のコンストラクタは」
( Wincore.cpp より抜粋)
CWnd::CWnd()
{
AFX_ZERO_INIT_OBJECT(CCmdTarget);
}
(抜粋ここまで)
「コンストラクタのメンバ関数名は、クラスと同じ」
『ホントだ同じだ』
「でも cWnd.CWnd() とか呼べないからね」
『げ、呼べないの?』
「そう、呼べないの。これは〈クラス名と同じメンバ関数は、コンストラク
タ〉って憶えるしかないかな」
『ないんだ』
「まー、 C++ 言語が悪いって言えば悪いんだけどね。あと、戻り値もない
から」
『あ、ホントだ。変数作る時に呼ぶから、いらないってこと?』
「そういうことだね」
『そういえば、 m_hWnd = NULL ってしてないけど、それしてるのが
AFX_ZERO_INIT_OBJECT() なんだ。全部大文字だからマクロ?』
「そう、このマクロで初期化してるんだけど……ちょっと難しいし、行儀悪
いことしてるからこれはパス」
『はいはい、いつものことねー』
「で、コンストラクタのまとめ。まず、変数は初期化しなきゃいけない」
『しないとメモリにあるのそのまま』
「その初期化をしてくれるメンバ関数が、クラスのコンストラクタ」
『メンバ関数っぽく呼ぶのと、何もしないで呼ばれるデフォルトのがある、
と』
「でもそのコンストラクタもちゃんと作られてて、そういう初期化の機能が
入ってないと意味がない、ってところかな」
『でも普通のクラスは初期化されてるんでしょ?』
「うーん、そうとも言い切れないかなー。たとえば CRect 」
void CAnimeDlg::OnBDraw()
{
CRect cRect;
TRACE( "%d\n", cRect.left );
// -858993460
}
『げ! 初期化されてない!』
「実際に CRect のコンストラクタを見てみましょう。あ、探してみて」
『はーい。えっと、【ファイルから検索】だよね。で、 CWnd::CWnd() と同
じになるってことは CRect::CRect() が CRect のコンストラクタ?』
「そうそう」
『じゃ、これで検索っと。あった』
( Afxwin1.inl より抜粋)
_AFXWIN_INLINE CRect::CRect()
{ /* random filled */ }
(抜粋ここまで)
『…… "random filled" って、つまりでたらめってことよね』
「そうなんだよねー。なんでこういう仕様にしてるかはちょっと不明」
『わざわざクラスにしてるんだからすればいいのに、初期化』
「うん、そう思う。 MFC ってこういう部分もあるからねー」
『あるからねーって』
「そう、これ大事」
『……何が?』
「 MFC だって人が作ったもの、ミスがあったりよく分かんない部分があっ
たり」
『でもそれ、いいわけにしかなんないじゃん』
「もちろん。そして、いつかそう言われるかもしんない立場に火美ちゃんが
なるかもしんない」
『……え”! つまりあたしが作ったクラスがそういうふうに批判されるっ
てこと!?』
「ま、そゆこと。 MFC だけじゃなく、世の中にはいろんなライブラリが
あって、いろんなクラスがあります。火美ちゃんも、いつかはそういうのの
仲間入りをするかもしれないわけ」
『なんかすごい話……』
「逆、逆。そういうのってすごそうに見えても、実はそうじゃないってこ
と」
『つまり、いつかはあたしが作れるもんなんだから、たいそうなもんじゃな
い?』
「心構えだけでもそう思っとかないと、そこまで辿り着けないよ?」
『なんかへっぽこな精神論に聞こえる……』
「まーね。たとえば」
void CAnimeDlg::OnBDraw()
{
CRect cRect;
::GetWindowRect( GetSafeHwnd(), cRect );
TRACE
( "%d, %d, %d, %d\n"
, cRect.left, cRect.top
, cRect.right, cRect.bottom );
}
『 Ver 7.08 ( No.127 ) のと同じ? ……あ、 cRect に & 付いてない』
「でも」
『ビルドできちゃう!? ちゃんと結果同じ!?? なんでぇ!?』
「というわけで次回に続く!」
/*
Preview Next Story!
*/
『? 「まーね、たとえば」ってどうつながるの?』
「これ、不思議な機能でしょ」
『アドレスじゃないのに通るなんて……』
「精神論だけじゃだめ、こういうのもちゃんと仕組みを知ってないとね」
『勉強もちゃんとしろ、と』
「そゆこと」
『というわけで次回』
< Version 7.09 演算子のオーバーロード >
「につづく!」
『結局医者と同じ、優しいだけじゃダメ、腕も立たないとね』
「わかってるじゃなーい!」
『はい!??』