Version 2.10
関数を作ろう!
「さて、今回は〈関数〉」
『かんすー?』
「そ。英語では Function ね」
『ふぁんくしょん』
「そう。関数っていうのは、前に使った MessageBox() とか、あとこれまで
ずっと使ってきた」
void CCalcDlg::OnBEqual()
{
}
「も関数のひとつ」
『これがいっぱい集まって、プログラムができてるとか言ってたよね』
「そう。だから一番大事なところかも。しっかりマスターしなきゃね」
『はーい』
「というわけで、関数を作ってみましょう」
『ええっ?? そんな簡単に作れるもんなの?』
「作れちゃうんだよね、これが」
// これが新しく作った関数!
void Test()
{
TRACE( "テストでーす\n" );
}
// 今までの関数。
void CCalcDlg::OnBEqual()
{
Test(); //上の関数を呼びだしてます。
}
『下のは今までのと同じだよね。上のが新しい関数なんだ』
「そ。これを順序ごとに見ると、」
void Test()
{
// 2
TRACE( "テストでーす\n" ); //3
// 4
}
void CCalcDlg::OnBEqual()
{
// 1
Test(); //上の関数へ。
// 5
}
「って順番かな。あ、もしよく分からなかったら、Ver.2.3 や 2.5 で使っ
たブレークポイントとかで、どんなふうに進むのか実際に試してみてね」
『……あのさー、これって、意味なくない?』
「っていうと?」
『だって、これと同じじゃない』
void CCalcDlg::OnBEqual()
{
// 1
// Test();
{
// 2
TRACE( "テストでーす\n" ); //3
// 4
}
// 5
}
「そうだよ」
『そうだよってねー……』
「でもさ、ちゃんとメリットもあるんだよ。たとえば変数とか。とりあえず
これ試してみて」
void CCalcDlg::OnBEqual()
{
int iBox
= 0;
int iBox //エラー!
= 0;
}
『あ、ビルドしたらエラーが出た』
「こんなふうに、同じ名前の変数はいくつも作れないんだけど、関数を使う
と……」
void Test()
{
int iBox
= 0;
TRACE( "テストでーす\n" );
}
void CCalcDlg::OnBEqual()
{
int iBox
= 0;
Test();
}
『あ、今度は大丈夫! なんで?』
「これは、関数はそれぞれ完全に独立してるから」
『どゆこと?』
「続いてこれも試してみましょう」
void Test()
{
iBox = 100; //エラー!
TRACE( "テストでーす\n" );
}
void CCalcDlg::OnBEqual()
{
int iBox
= 0;
Test();
}
『あれ? エラー出ちゃったよ』
「つまり、 CCalcDlg::OnBEqual() の中で作った iBox って変数は、Test()
の中じゃ影も形もないってこと」
『あ、それが〈独立してる〉ってことなんだ』
「プログラムが大きくなってくると問題になるのが、変数がいつの間にか書
き換えられちゃうこと。でも、小さい関数をいっぱい作るようにすれば、書
き換えられる範囲が特定できるでしょ」
『確かにおっきな水槽に金魚入れとくといつの間にかいなくなっちゃったり
するけど、ちっちゃな金魚鉢ならそういうことないもんね』
「……まあ、そういうことかな。で、もうひとつのメリット」
void Test()
{
TRACE( "テストでーす\n" );
}
void CCalcDlg::OnBEqual()
{
Test();
TRACE( "テストでーす、2!\n" );
}
『ん? これってなんの変哲もないプログラムって感じ。 TRACE() を両方
で使ってるだけよね』
「その TRACE() 、これも関数みたいなもんなんだけど、もしこの TRACE()
と同じ機能を持つプログラムを貼り付けるとしたら?」
『あ、それ面倒……』
「関数にすると、こういうふうにいろんなところから何度でも呼べるように
なるから、実際にプログラムとして書くよりもずっと楽でしょ」
『だから関数にした方がいいってことね〜』
「そういうこと。まとめると、関数はそれぞれが独立してて、お互いを呼び
合ってプログラムを構成してます」
『その関数を作っていって、組み上げるってことがプログラミングってこと
ね。でもさ、素朴な疑問なんだけど……』
「なに?」
『独立してるんだったら、ものすごく困んない? たとえばロボットとかな
ら、腕と胴体とか、シャフトとかコードとかで継ながってるよね』
「そう。関数にも、そういう〈関数どうしでデータをやりとりする方法〉が
ちゃんとあります。たとえば TRACE() に "テストでーす\n" を渡してるよ
うにね」
『あ、これがそうなんだ』
「そう。この渡すものを〈引数〉っていいます」
『ひきすう?』
void Test
( int iBox ) //これが引数!
{
TRACE( "引数は %d です。\n", iBox );
// 引数は 100 です。
}
void CCalcDlg::OnBEqual()
{
Test( 100 );
}
「この int iBox が引数」
『あれ? これって変数作るのと同じだね』
「そう、これまでの int iBox と同じ、変数を作ってるだけ。だから、
Test( 100 ); のところの引数は int iBox = 100 ってしてるってことかな」
『変数作ってそこに数字入れてるんだ。こうやって情報を渡せるのねー』
「もちろん iBox は普通の変数と同じだから、計算とかもできるから。で、
もうひとつの方法、〈戻り値〉も見ておこうか」
『もどりち?』
int //これが戻り値!
Test()
{
return 100; //戻り値を返します。
}
void CCalcDlg::OnBEqual()
{
int iBox
= Test();
TRACE( "戻り値は %d です。\n", iBox );
// 戻り値は 100 です。
}
『void っていうのが int になったね』
「そう。これを int にすることで〈数字を返すよ!〉っていう意味になる
わけ」
『返すって?』
「前に〈置き換える〉っていうのあったでしょ」
『 3 < 5 が 1 に、 3 > 5 が 0 に置き換わるってヤツ?』
「そうそう。これと同じで、ここでは〈 Test() は呼び出したあと数字に置
き換わります〉ってことになるわけだね」
『へー。で、Test(); が100に置き換わって、それが iBox に入るってこ
とね。その100を返してるのが、return ってこと?』
「そう。return を使うと、そこで関数が終わって、return に渡した値を戻
り値にします」
『ふーん』
「じゃ、問題」
『げ!』
「引数に数字を取って、それを1増やして、戻り値として返す関数を作って
みて」
『え、えっと……ってことは、引数も戻り値も、 int でいいんだから……』
int Test( int iBox )
『みたいな感じにして…… return に変数って使えるの?』
「もちろん!」
『ってことは……』
{
return iBox + 1;
}
『ってすれば、戻り値は引数に1足したのになるから……これで終わり?』
「そ。まとめると?」
『こんな感じかな』
int Test( int iBox )
{
return iBox + 1;
}
void CCalcDlg::OnBEqual()
{
int iBox
= Test( 10000 );
TRACE( "戻り値は %d です。\n", iBox );
// 戻り値は 10001 です。
}
『ビルドして実行……ちゃんと1増えてる!!』
「どう? 関数を作ってみた感じは」
『とりあえず楽勝って感じ?』
/*
Preview Next Story!
*/
『関数作ったら、今度は?』
「今度は使い方」
『それって順序逆じゃない?』
「そうとも言えないんだよねー」
『というわけで次回』
< Version 2.11 関数を使おう! >
「につづく!!」
『なんか、教える順番ぐちゃぐちゃじゃない?』
「ぎくっ」