Version 13.12
コレクションを使ってみよう
「バリエーションの最後として、今回は配列以外のものを使ってみます」
『配列以外?』
「配列には〈サイズを変えられない〉〈サイズがわからない〉などのデメ
リットがあります。そこで、配列の機能を持ったクラスが作られました」
『それが配列以外のものってことね』
「そう。一般には【コレクション】って呼ばれます」
『コレクションって、集めるとかゆー意味の?』
「そのコレクション。コレクションには色々な種類があるんだけど、とりあ
えず MFC にある CString 専用コレクション CStringArray を紹介します」
void Use_CStringArray()
{
CStringArray cStrAry;
cStrAry.Add( "CCC" );
cStrAry.Add( "BBB" );
cStrAry.Add( "AAA" );
cStrAry.Add( "EEE" );
cStrAry.Add( "DDD" );
for( int iF1 = 0; iF1 < cStrAry.GetSize(); ++iF1 )
{
TRACE( "%s ", cStrAry.GetAt( iF1 ) );
}
TRACE( "\n" );
// CCC BBB AAA EEE DDD
}
『 Add() ってメンバ関数で追加して、 GetSize() ってメンバ関数で数が取
得できるのね』
「このふたつが配列との違い、かな。データを削除することもできるから」
『で、 GetAt() でデータを取り出すわけね。この CStringArray を使う
と、ソートするときにいいことあるの?』
「あんまりない」
『え”』
「前も言ったように、ソートはサイズは変わらないから、データの追加や削
除は特に必要ないんです。サイズ取得が便利っていうくらいかな」
『じゃあ使う意味ないんじゃ……』
「でも、ソートを使う側は便利だと思うよ。 Version 13.10 ( No.246 ) の
この例と比べてみて」
const char *ppchAry[5];
ppchAry[0] = "CCC";
ppchAry[1] = "BBB";
ppchAry[2] = "AAA";
ppchAry[3] = "EEE";
ppchAry[4] = "DDD";
「 "CCC" とかは【文字列リテラル】、 Version 5.06 ( No.071 ) で説明し
たようにメモリ上に置かれた文字列。でも、普通ソートするのって普通の文
字列でしょ」
『そうだね』
「そうなると、数とかサイズ普通可変だから」
『 CString が使えて、しかも追加できる CStringArray の方が便利……』
「そういうこと。では、 CStringArray を使う場合のソートの例」
// p_pchL > p_pchR なら true を、
// それ以外は false を返すようにしてください。
bool CompareTo( const char *p_pchL, const char *p_pchR )
{
if( strcmp( p_pchL, p_pchR ) > 0 )
{
return true;
}
return false;
}
void DoBubbleSortToCStringArray( CStringArray &p_rcStrAry )
{
// 「入れ替え先」のループです。
for( int iOut = 0; iOut < p_rcStrAry.GetSize() - 1; iOut++ )
{
// 最後から先頭方向へのループです。
// ただし「入れ替え先」までです。
for( int iIn = p_rcStrAry.GetSize() - 1; iOut < iIn; iIn-- )
{
if( CompareTo
( p_rcStrAry.GetAt( iIn - 1 )
, p_rcStrAry.GetAt( iIn )
)
== true )
{
// 前の方が大きいので入れ替えます。
CString cTempStr = p_rcStrAry.GetAt( iIn );
p_rcStrAry.SetAt( iIn, p_rcStrAry.GetAt( iIn - 1 ) );
p_rcStrAry.SetAt( iIn - 1, cTempStr );
}
}
}
}
「使用例はこんな感じ」
void Use_DoBubbleSortToCStringArray()
{
CStringArray cStrAry;
cStrAry.Add( "CCC" );
cStrAry.Add( "BBB" );
cStrAry.Add( "AAA" );
cStrAry.Add( "EEE" );
cStrAry.Add( "DDD" );
// ソートします。
DoBubbleSortToCStringArray( cStrAry );
for( int iF1 = 0; iF1 < cStrAry.GetSize(); ++iF1 )
{
TRACE( "%s ", cStrAry.GetAt( iF1 ) );
}
TRACE( "\n" );
// AAA BBB CCC DDD EEE
}
『使用例はさっきとほとんど同じね』
「ソートの部分もほとんど同じ。違うところは、まず引数にサイズを渡して
ない点」
『サイズは GetSize() で取得できるんだものね』
「だから、ソートの部分もこう変わります」
// 「入れ替え先」のループです。
for( int iOut = 0; iOut < p_rcStrAry.GetSize() - 1; iOut++ )
{
// 最後から先頭方向へのループです。
// ただし「入れ替え先」までです。
for( int iIn = p_rcStrAry.GetSize() - 1; iOut < iIn; iIn-- )
{
『あ、ここって変わらないはずなのに……』
「サイズの取得方法が変わったからね。やってることは一緒」
『うーん……』
「他も基本的には同じかな。比較関数も今までと同じだし」
『ん……質問!』
「はい火美ちゃん」
『入れ替える部分がよくわかんない』
CString cTempStr = p_rcStrAry.GetAt( iIn );
p_rcStrAry.SetAt( iIn, p_rcStrAry.GetAt( iIn - 1 ) );
p_rcStrAry.SetAt( iIn - 1, cTempStr );
「基本的には、配列の時と同じ。 CStringArray::GetAt() でデータを取得
して、 CStringArray::SetAt() でデータをセット。 SetAt() は第1引数が
インデックスナンバー、第2引数がセットする値」
p_rcStrAry.SetAt( iIn, p_rcStrAry.GetAt( iIn - 1 ) );
「と」
p_rcStrAry[iIn] = p_rcStrAry[iIn - 1];
「が同じってこと」
『ちょっとややこしい……』
「それは言えるかも。ちなみに」
CString cTempStr = p_rcStrAry[iIn];
p_rcStrAry[iIn] = p_rcStrAry[iIn - 1];
p_rcStrAry[iIn - 1] = cTempStr;
「でも、実はできちゃいます」
『え!? なんで配列みたいに [] が使えるの?』
「それは、演算子のオーバーロードをしてるから」
『あ、 Version 7.09 ( No.129 ) でやったやつ?』
「そう。 CStringArray は [] をオーバーロードしていて、配列のように
データを返してくれるんです」
『へー』
「まぁ実はそれだけじゃなくて、かなり複雑な仕組みだったりするんだけど
ね」
『え?』
「まぁそれはまたの機会に」
『むー。あ、そうそう、もうひとつ質問!』
「はい火美ちゃん」
『これって、 CString のコピーしてるじゃない。ポインタのコピーしてな
いんだから重くなるんじゃない?』
「それはちょっと複雑な部分だね。まず、この処理では文字列のコピーは行
われていません」
『え、そうなの?』
「 CString から CString にコピーすると、中に持っている文字列ポインタ
だけをコピーするんです」
『ってことは同じ……? それって、ふたつの CString が同じ文字列ポイ
ンタを持つってこと? それじゃ、一方が文字列書き換えたらもう一方も書
き換わっちゃうんじゃない?』
「その辺はちゃんとしていて、文字列の中身が変えられる時には新しく文字
列領域を確保するから」
『一緒に書き換わることはないわけね……』
「そういうこと。 CStringArray の使い方はこんな感じかな」
『え? コレクションってこれだけ?』
「ううん、まだいっぱいあるよ。というわけで次回に続く!」
/*
Preview Next Story!
*/
『文字列追加ってよくありそうだから、これは便利だよね』
「これを利用すればエディタとかも作れるかな」
『1行1要素みたいな?』
「そういうこと。次回のポインタ用のも使うと、さらに幅が広がるから」
『というわけで次回』
< Version 13.13 ポインタ用コレクション >
「につづく!」
『じゃあもう new しなくても大丈夫?』
「ううん、それは必要」
『げ』