Version 5.22
文字列クラス
「さて、ブラッシュアップ編も最終回です」
『うう、やっと終わり……で、今日は?』
「また蒸し返すことになるけど」
char chDest[256];
『 while の外に出せばいいんじゃないの?』
「それはそう。それとは別に、ここでは char の配列を使ってるけど、他の
方法を使ってみましょう」
『それってもしかして CString のこと?』
「そう、これまでも何度も使ってるこのクラス」
『 Ver 5.19 ( No.084 ) でも使ったよね』
「まだ踏み込んで中を見ていくほど火美ちゃんもレベル高くないから」
『うー』
「今回はさわりくらいで。まず、文字列の基本は char chDest[256]; って
感じの配列。これは CString でも変わりません」
『変わんないの?』
「変わんないです。 CWnd の中に HWND m_hWnd が入ってたの憶えてる?」
『ウィンドウハンドルだよね。そっか、 CString の中にはその配列が入っ
てるってことなんだ』
「そういうこと。ただーし、この〈普通の配列〉だと、問題があります」
『問題? あ、サイズ変えられない!!』
「そゆこと。この例だと 256 文字分しか入らないからね」
『でもさ、 char chDest[i]; とかっていうのはダメなんだよね』
「そう、だから別の方法を使います。ファイル使ったときにちょっと触れた
と思うけど、変数を好きなときに作って好きなときに削除する方法が」
『あった! そうそう、 fopen() して fclose() するみたいな』
「そういう仕組みが C++ 言語には備わってます。それは new と delete 」
int i;
char *pchDest = new char[256]; // ここと。
while( 1 )
{
cIFStrm
>> i;
if( cIFStrm.eof() )
{
break;
}
if( cIFStrm.fail() )
{
MessageError( IDS_E_NONINT );
return;
}
sprintf( pchDest, "%d", i );
m_cDataLstBox.AddString( pchDest );
}
delete[] pchDest; // ここ。
『まず作ってるとこがかなり変わったね』
char *pchDest = new char[256]; // ここと。
『 = の左側はいつもと同じ、単にポインタ作ってるだけだね』
「右の new は、 C++ の演算子のひとつ」
『演算子なの?』
「そ、 sizeof も演算子だったでしょ。それと同じ」
『 Ver 5.07 ( No.072 ) でそんなこと言ってたね』
「 new はその場でいきなり変数を作ることができます。たとえばこの例な
ら char 型の変数を256個いっぺんに作っちゃいます」
『それが配列として使えるってこと?』
「そ、作られた変数はメモリ上にずらっと並んでる、ってイメージかな」
『それをポインタで受け取るんだ』
「この例だと分かりにくいから、もひとつ簡単な例を紹介すると」
int *pi = new int;
『ん、 int 型変数を……1個作ってるの?』
「そう、 [] がなければ1個だけ。で、これもポインタで受け取ってるで
しょ」
『うん受け取ってる』
「思い出して、ファイルポインタも」
『ポインタだ!』
「こういう〈変数の動的生成〉をするときには、メモリ上にその変数の領域
を確保して、そのポインタを受け取ってそれで操作する、って形式が普通」
『なんで?』
「作った変数が〈なくなったとき〉を表せないから」
『??』
「普通の変数なら、寿命がある限りいつでもどこでも使えるでしょ」
『そだね、勝手になくなんないね。 fclose() でなくしたら、そのあとは使
えないんだった……あ! そっか、 NULL 入れればいいんだ!』
「そゆこと。ポインタとして持ってて、解放したら、 NULL を入れて〈もう
持ってません〉ってことにできるわけ。 Ver 5.11 ( No.076 ) でやったね」
『そゆときに便利なんだ』
「それに、〈サイズを変える〉場合には同じアドレスになんないことが多い
から」
『どゆこと?』
「128サイズの領域を作る、サイズが足りなくなった、256サイズの領
域を作ってコピー、128サイズの方を削除」
『128サイズのアドレスと256サイズのアドレスは違うから、ポインタ
の中のアドレスを置き換えることになっちゃうんだ』
「そういうこと。だからポインタ」
『メモリに確保して、それをポインタとして受け取る、んでポインタで操作、
ね』
「使うのはポインタとしてそのまま何気なく使えます」
『うん、使ってるね。特に文字配列はポインタとして使うからほとんど同じ』
「で、最後に解放。これは delete 演算子でします」
delete[] pchDest; // ここ。
『 delete のあとの [] は?』
「2個以上確保したら [] 付けるきまりになってるから。だから、1個の」
int *pi = new int;
「の場合には」
delete pi;
「でOK」
『なんかちょっとややこしい……けど、はっきし言ってそんな難しくない
よ?』
「たったこれだけならね。たとえば」
char *pch2 = pchDest;
「ってポインタをコピーして」
delete pch2;
『2度削除しちゃう!!』
「そゆこと。さらに、他の関数やクラスを超えて使うようになると……」
『つまり、管理が大変ってことなのねー』
「だから CString を使うのです!!」
『うお!』
「自分で管理をするのは大変、だから管理専用クラスに任せちゃう方がい
いってこと」
『なるほどー』
「で、こんな感じになります。最後だから関数全体!」
void CFileTestDlg::OnBtnShow()
{
m_cDataLstBox.ResetContent();
std::ifstream cIFStrm;
cIFStrm.open( "Data.txt" );
if( cIFStrm.fail() )
{
MessageError( IDS_E_NOFILE );
return;
}
int i;
CString cDestStr;
while( 1 )
{
cIFStrm
>> i;
if( cIFStrm.eof() )
{
break;
}
if( cIFStrm.fail() )
{
MessageError( IDS_E_NONINT );
return;
}
cDestStr.Format( "%d", i );
m_cDataLstBox.AddString( cDestStr );
}
}
『 CString 型の変数 cDestStr 、サイズ決めなくていいの?』
「 CString は自動的にサイズを決めてくれるんです。たとえば」
cDestStr = "ABC";
「ってしたら4文字分のサイズにしてくれるんです」
『おー! あと Format() ってメンバ関数は、 sprintf() と同じ機能?』
「そう、 CString には便利なメンバ関数がそろってて、これもそのひとつ」
『リファレンス見るといっぱいあるもんね。 operator = って?』
「 operator っていうのはクラスに演算子を持たせるもの」
『はっ、もしかして std::ifstream で使った << ってこれ?』
「そういうこと。これは = 演算子だから……あ、そう、上の "ABC" 入れて
るのがこの演算子を使った例」
『あ、そーなんだ。ってことは、普通のクラスはこういうことできないって
こと?』
「そゆこと。できるようにするには operator を使わないといけないわけ」
『これはさすがに難しそう……』
「あと……ちょっと CListBox::AddString() のリファレンス見てみて」
『ほい F1 。あ、受け取る型が LPCTSTR なのに CString 渡せてる、って前
にもそういうことあったね』
「そう、で、また CString のメンバ関数一覧を見て、 operator LPCTSTR
ってあるでしょ」
『うお、なんかいかにもって感じ!』
「これは LPCTSTR 型を求められてもうまく処理できるよう operator で設
定されてるってこと」
『だから CString を渡せるんだ』
「 LPCTSTR を求められたら中の文字列へのポインタを返すようになってる
から、うまくいくわけ」
『ほー』
「ほーって、も少したったら自分でこれくらい書けるようになってもらうか
ら」
『げげ!』
/*
Preview Next Story!
*/
『とりあえずブラッシュアップ終了! で、次は?』
「次からはウィンドウについて」
『ウィンドウはもう結構やったと思うんだけど』
「ところがウィンドウズの世界は奥が深いんだよね……」
『というわけで次回』
< Version 5.23 ウィンドウクラス >
「につづく!」
『ほんっと、教えても教えてもキリがないって感じね』
「そんだけウィンドウズプログラミングが大変って証拠かも」