Version 11.23
文字列編まとめ
「さて、文字列編は実は今回が最後です」
『む? なんか文字列編って感じじゃなかったよーな』
「でも CString の仕組みはだいたいわかったでしょ?」
『そういえば演算子のオーバーロードとか仕組みはわかったから、それが
CString に使われてるんだなーってのは』
「そのくらいでいいから。今はまだ使う側だけ。作ってみたのは、使うため
にもう少し理解した方がいいかなと思って」
『確かに中身わかってると大きいかも』
「さて、今回はそういった部分も含めてまとめてみます」
『最初は文字とか文字列とかの基本的な部分だよね』
「やっぱり \ の部分が一番重要かな」
『これはホントやっかいよねー。ソが嫌いになりそう……』
「でも _mbsbtype() とかを使えばいいから、それさえ守れば大丈夫だと思
うよ」
『あ……質問! CString 使う時はどうすればいいの? そのときもこれ使
うの?』
「 CString の場合は場合によるかな。たとえば、 CString::Find() ってメ
ンバ関数は文字列の検索をしてくれるメンバ関数なんだけど、これはちゃん
と文字種のチェックをしてくれるんです」
void Use_CString_Find()
{
CString cStr = "ソフト\\です";
TRACE( "%d\n", cStr.Find( "\\" ) );
// 6
}
『お、ちゃんと最初のソにひっかからない』
「だから、こういう CString のメンバ関数を使っていれば大丈夫。ただ、
CString.GetAt() っていう、1 char ずつ取得するメンバ関数があるんだけ
ど、こういうのを使う場合には必要かな」
『でも、 CString のをどうやって _mbsbtype() に渡すの?』
「試してみようか」
void OutputFileName3()
{
CString cStr = "C:\\Test\\ソフト.txt";
CString cOutStr;
int iCharType = _mbsbtype( (unsigned char *)"\\", 0 );
// 後ろから見ていきます。
for( int iIndex = cStr.GetLength() - 1; 0 <= iIndex ; iIndex-- )
{
// 文字種も含めてチェック。
if(
( cStr.GetAt( iIndex ) == '\\' ) &&
( _mbsbtype
( (unsigned char *)(LPCTSTR)cStr
, iIndex
) == iCharType
)
)
{
// \\ がみつかりました。
// その次の文字から最後まで取り出します。
cOutStr = cStr.Mid( iIndex + 1 );
break;
}
}
// 出力します。
TRACE( "%s\n", cOutStr );
}
『 Version 11.04 ( No.204 ) の OutputFileName2() の CString 版ね』
「結構違うところあるでしょ」
『うん、 Mid() ってゆーの呼んでたりしてる』
「その辺の、 CString の使い方についても含めて見ていこうか。まず」
for( int iIndex = cStr.GetLength() - 1; 0 <= iIndex ; iIndex-- )
「 CString::GetLength() で、 CString が持ってる文字列のサイズが取得
できます」
『 strlen() の代わりね』
「次は文字を取る部分」
( cStr.GetAt( iIndex ) == '\\' ) &&
『これがさっき言ってた1文字取るメンバ関数ね。 [] の代わりってとこ
ねー』
「ちなみに CString::operator[]() っていうのもあって」
『 [] のオーバーロード……ってことは』
( cStr[iIndex] == '\\' ) &&
「っていう配列っぽい使い方もできるんです」
『へー、ちょっとかっこいいかも……』
「次は _mbsbtype() に渡す部分」
( _mbsbtype
( (unsigned char *)(LPCTSTR)cStr
, iIndex
) == iCharType
)
『う”、なんか2回キャストしてる……』
「まず」
( (unsigned char *)cStr
「だとコンパイルエラーになります」
error C2440:
'type cast' : 'class CString' から 'unsigned char *'
に変換することはできません。
『あらま』
「で、基本に返って考えてみて、 CString を普通の文字列として使えるの
はなぜでしょう」
『?』
「つまり」
const char *const pchData = cStr;
「みたいなことができるのはなんでかってこと」
『あー、確かその型に変換してくれるんだよね、型変換のオーバーロード
で』
「そう、 CString::operator LPCTSTR() があるから。でも、この型変換は
LPCTSTR だけにしか変換できないんです。で、 LPCTSTR ってなんだっけ」
『 Version 5.08 ( No.073 ) でやったよ、 const char * だって。だから
さっきのがうまくいくんでしょ?』
「そういうこと。だから、 const char * じゃないとうまくいかない、つま
り」
『 unsigned char * だとうまくいかない!』
「そういうこと! unsigned char * が求められても LPCTSTR とは違うか
ら、このメンバ関数が呼ばれないんです」
『だからコンパイルエラーね』
「だったら、というわけで、まず CString::operator LPCTSTR() を無理矢
理呼び出します」
(LPCTSTR)cStr
『う”、キャストしたら呼び出されるわけね、でもなんか変……』
「だね。そういうメンバ関数が別に用意されてたらよかったんだけど……
で、これなら CString::operator LPCTSTR() が呼ばれて、これは普通の文
字列ポインタ、つまり const char * だから」
『これなら unsigned char * にキャストできる、と』
「そういうこと。だからああいうふうにしてるんです」
『なるほどねー』
「最後にこの部分」
cOutStr = cStr.Mid( iIndex + 1 );
『 CString::Mid() ってメンバ関数だね。リファレンス見ると……文字列を
取り出す?』
「そう、 CString::Mid() は第1引数から第2引数までの範囲で文字列を取
り出して返してくれます。第2引数を省略すると最後の文字までってなりま
す」
『あれ? でもさ、 CString::Right() とかあるけど、こっちの方が良くな
い?』
「 CString::Right() は〈文字列の最後から指定した文字数だけ取り出す〉
ってメンバ関数。今回の例の iIndex って文字列の先頭からの文字数だか
ら、 CString::Right() に使う時には」
『最後からの文字数にしなきゃいけない、と』
「そゆこと。だから今回は CString::Mid() の方が便利だから」
『でも、少なくとも CString はそういうの揃ってるから便利よね』
「もちろんそれだけじゃないよ」
『 new と delete 使ってるから文字列の長さを気にしなくていいし、コン
ストラクタとデストラクタで処理してくれるからその辺も気にしなくてい
い、だよね』
「そういうメリットも多いから、当分は CString 中心でね。さっきの例を
参考にすれば、 CString とランタイムを組み合わせるのもできるでしょ」
『うん、大丈夫だと思うよ』
「最後に、くれぐれも前回みたいな使い方はしないようにね」
『 CString の戻り値は CString で受け取ればいい、んだよね』
「そういうこと。というよりそもそも」
CString cStr = "あいうえお";
const char *pch = cStr;
「って使い方自体が間違ってるかも」
『え? 結構普通っぽいのに』
「この例だと、 pch の中には cStr の中の文字列ポインタが入ってるわけ
でしょ」
『うん』
「で、ここで Version 11.15 ( No.215 ) の文字列をくっつける例を思い出
して」
『確か、文字列に文字列を加える時って、両方とも入る分だけ新たに確保し
直して……あ”』
「わかった?」
『 cStr += "かきくけこ" とかしたら、 pch のポインタ、ダメなんじゃな
い?』
「そういうこと。だから、こういうふうにポインタに入れないようにして、
使う時は必ず関数への引数に渡すようにする、って感じかな」
『関数の引数なら大丈夫?』
「関数から抜ければポインタはなくなるわけだから」
『なるほどね』
「簡単に使える CString だけど、危険な部分はいっぱいあるから。今使っ
てる方法が本当に正しいのか、常に考えるようにね」
『……そのために、 malloc() とか new とか、コンストラクタとかの勉強
をしたってこと?』
「そういうこと」
/*
Preview Next Story!
*/
「というわけで次回からは文字列以外の話をします」
『……? なんか表現がへんくない?』
「っていうのも、文字列と関係した話だから」
『げ、まだ続くんだ』
「しかもきっと、今までで一番難しい話が出て来ます」
『げげげ!』
「というわけで次回」
< Version 12.01 文字列じゃない世界 >
『につづく!』
「覚悟してね」
『いや〜!』