Version 5.20
ファイル読み込みをさらにブラッシュアップ!
「前回までで、 CFileTestDlg::OnBtnShow() はこんな感じになってます」
void CFileTestDlg::OnBtnShow()
{
m_cDataLstBox.ResetContent();
int i;
std::ifstream cIFStrm;
cIFStrm.open( "_Data.txt" );
if( cIFStrm.fail() )
{
CString cStr;
cStr.LoadString( IDS_E_NOFILE );
const int iIDOffset = 1000;
CString cStrCap;
cStrCap.LoadString( IDS_E_NOFILE + iIDOffset );
MessageBox
( cStr, cStrCap
, MB_OK | MB_ICONEXCLAMATION );
return;
}
while( !cIFStrm.eof() )
{
cIFStrm
>> i;
if( cIFStrm.fail() )
{
TRACE( "整数値じゃないです\n" );
return;
}
char chDest[256];
sprintf( chDest, "%d", i );
m_cDataLstBox.AddString( chDest );
}
}
『今はファイル読み込みの所のエラー処理をしてるんだよね』
「そうです。でもちょっと下の方見てみて。こっちでもエラー処理してるで
しょ」
『あ、ホントだ、 TRACE() でエラー出してるね』
「ここにも同じコードを書くのは無駄だから、エラー処理を外のメンバ関数
として作ることにします。他の部分でもエラー処理が必要になるかもしれな
いしね」
『へー、そういうことできるんだ』
「同じ部分は関数にまとめる、それが基本。プログラムがすっきりして見や
すくなるし、間違いを直すのも1ヶ所だけで済むからね」
『そりゃそうよねー、同じとこいっぱいあったら全部直さなきゃ行けないも
んね』
「ではまず、メンバ関数を作ってみましょう。今までは〈あるイベントに対
応するメンバ関数〉しか作ってこなかったけど」
『 CFileTestDlg::OnBtnShow() がそうだね』
「もちろん普通のメンバ関数も作れます。ワークスペースの【Class View】
を見て」
『ワークスペースってリソースとかソースファイルとか色々載ってるのだよ
ね。そのクラスのっと』
「 CAboutDlg とか CFileTestApp とかあるでしょ」
『 CFileTestDlg もね。このクラスにメンバ関数付けるんだよね』
「そう、 CFileTestDlg::OnBtnShow() から呼び出すから同じクラスにしま
す。この【Class View】で CFileTestDlg を右クリックして、メニューか
ら【メンバ関数の追加】を選んで」
『ダイアログ出たよ』
「【関数の型】はメンバ関数の戻り値のこと」
『 void でいい?』
「ホントはこういうのはちゃんと考えなきゃいけないんだけど、考えたくな
い時は bool で」
『なんで?』
「ちょっとエラーを返したい時とかに便利だから」
『あー』
「【関数の宣言】はメンバ関数の名前と引数。こんな感じにして」
MessageError( unsigned int p_puiID )
『 unsigned int の引数?』
「 IDS_E_NOFILE とかの ID を引数に渡すから」
『あー』
「 unsigned なのは ID だから。 ID は符号なしだからね」
『他は?』
「【アクセス制御】は Private にしといて。これはちょっと難しいから説
明は結構あとで。これで完了」
『んじゃ OK っと』
「こんなのが CFileTestDlg::OnBtnShow() の下にできたと思うよ」
bool CFileTestDlg::MessageError(unsigned int p_puiID)
{
}
『おおっ、メンバ関数!』
「ではさっきのエラー処理の部分を書き込んで、ちょっと手直ししてこんな
感じに」
bool CFileTestDlg::MessageError(unsigned int p_puiID)
{
const unsigned int iIDOffset = 1000;
CString cStr;
cStr.LoadString( p_puiID );
CString cStrCap;
cStrCap.LoadString( p_puiID + iIDOffset );
MessageBox
( cStr, cStrCap
, MB_OK | MB_ICONEXCLAMATION );
return true;
}
『えーっと、違うところは…… iIDOffset 作ってるとこが最初に来てるね』
「別に最初じゃなくてもいいんだけど、これは気分で」
『その方が見やすいもんね。あと CString::LoadString() に渡してるのが
IDS_E_NOFILE から p_puiID になってるね』
「つまり引数として渡された値を ID としてエラーメッセージを取り出すっ
てこと。そして、呼び出す側はこうなります」
if( cIFStrm.fail() )
{
MessageError( IDS_E_NOFILE );
return;
}
『うおすっきり!』
「とりあえず試してみて」
『ビルドして実行して【表示】ボタン! うんちゃんとさっきと同じダイア
ログが出た』
「こういうふうに関数にまとめるの、めんどくさがっちゃダメだからね」
『分かってるよー、後から直すときとか大変なんだもんね。次は?』
「じゃ、後半の while に移ろうか。まず」
TRACE( "整数値じゃないです\n" );
「を今の関数に置き換えちゃおうか」
『そだねー。えーっと、まずストリングテーブルに追加しないと』
IDS_E_NONINT=202 : 整数値じゃないです
IDS_E_NONINT_C=1202 : 整数値じゃないです
『でいい?』
「うーん…… IDS_E_NONINT の方は〈ファイル中に整数値以外のデータが含
まれています。\nファイルを確認してください〉の方がいいかな」
『あ、複数行 OK なんだ。改行には \n を使うんだね』
「直接書き込むときには、改行は」
『リターンキー押すとダイアログが消えちゃう!』
「から、 Ctrl キーを押しながらリターンキーを押せば」
『改行された!』
「これでも改行できるし、 \n でもできるから」
『じゃー前回の〈ファイルがありません〉もそうした方がいいかな』
「そうだね、だからまとめると」
IDS_E_NOFILE=201
: ファイルが見つかりませんでした。
\nファイル名を確認してください。
IDS_E_NOFILE_C=1201 : ファイルがありません
IDS_E_NONINT=202
: ファイル中に整数値以外のデータが含まれています。
\nファイルを確認してください
IDS_E_NONINT_C=1202 : 整数値じゃありません
「ってとこかな。まー実際、この文だけじゃ分かりにくいんだけどね、使っ
てる側からすれば」
『そだね、なんかでフォローしないと』
「じゃ、呼び出す部分は?」
『 ID を変えればいいだけだから』
MessageError( IDS_E_NONINT );
「だね。じゃ、今回最後は char chDest[256] について。そうだね、とりあ
えず試してみようか。 while のあとに次の行追加して」
} // while の区間を閉じる中カッコ。
TRACE( "%s\n", chDest ); // この行を追加。
} // CFileTestDlg::OnBtnShow() を閉じる中カッコ。
『あ、 chDest を表示するのだね。んじゃビルドして』
error C2065: 'chDest' : 定義されていない識別子です。
『げ! エラーになっちゃった』
「 chDest って while の中で宣言してるでしょ。実は、この chDest の寿
命はこの while のあとの中カッコの中だけなんです」
『どゆこと?』
「 Ver 4.13 ( No.063 ) で〈変数の寿命〉を教えたでしょ」
『うん、関数抜けたら変数がなくなっちゃうってゆーの』
「実は、正確に言うと〈関数から抜けたら〉じゃないんです」
『え、そうだったの?』
「正確には〈対応する { と } から抜けたら〉」
『だから while の中カッコから抜けたら chDest がなくなってるんだ!』
「 { が複数回ある場合には、対応する } が来たら変数消える仕組み」
『つまり関数じゃなくて { } で考えればいいんだよね。っつーかインデン
トで考えればいいってゆーか』
「そだね、インデントする範囲って考えてもいいかも。ちなみに { } で囲
まれた区域を【ネスト】っていいます」
『ねすと?』
「〈何かの中に何かを入れる〉っていう意味。 while とか for とかのも、
ネストだからね」
『そういえば〈ネストが深い〉とかよくゆーもんね』
「もひとつ用語言うと、変数が生きてる範囲を【スコープ】っていいます」
『すこーぷ? あの銃とかに付いてる』
「それボケじゃなくて当たり。上の例で chDest がなくなっちゃってたら使
えないでしょ」
『うん使えない』
「ってことは〈見えない〉」
『あー、そういう意味でスコープなんだ。あ、それって、他の関数から変数
使えないのと同じ?』
「そう同じ。というわけで、ネストとスコープ、そして変数の寿命、その辺
を踏まえると、 chDest は while の前で宣言した方がいいことになるよね」
『どーして?』
「それは宿題」
『げげ!』
/*
Preview Next Story!
*/
『宿題ってゆーより、スペースがたんなくなったんでしょ』
「っていうか、ブラッシュアップでこんなに量がかかるなんて」
『でもさ、この前も言ってたけど、こういうの本に載ってないよね』
「なんだよね、絶対必要な技術だと思うんだけど……」
『というわけで次回』
< Version 5.21 ファイル読み込みをさらにさらにブラッシュアップ! >
「につづく!」
『もしかしてほとんどのプログラマーはこゆことしてないんじゃない?』
「あ、ありうる……」