Version 13.13
ポインタ用コレクション
「前回は CStringArray について見てみました」
『でもコレクションってこれだけじゃないんだよね』
「そうなんだけど……構造体とかでコレクションを使う時にはちょっと難し
くなるかな」
『どういうこと?』
「まず、 CStringArray みたいに、特定の型のコレクションが用意されてい
るのは珍しいこと。普通のクラスには、専用のコレクションクラスなんてあ
りません」
『そりゃそうよね。それほどすごい数のコレクションクラスが必要になっ
ちゃうもの』
「でも、コレクションクラスでどんな型でも扱えるようにするためには一工
夫必要になるんです。型が違うとコンパイルエラーが出るから」
『そういえば……ってゆーか、どんな型でも、っていうの無理じゃない?』
「無理でもないよ。ひとつは、【テンプレート】っていうものを使う方法」
『テンプレートって、なんかの元になるってゆーか、使い回しにするものっ
てゆーか』
「そう、そのテンプレート。テンプレートを使うとどんな型にでも使えるよ
うになります。実際、 MFC の CArray とかはテンプレートの機能を使って
ます。だけど……」
『だけど?』
「上級者向けで、ちょっと簡単には使いにくいかな」
『えー?』
「というわけで、もうひとつの方法として、ポインタを使う方法を紹介しま
す。 void ポインタって憶えてる?」
『 Version 7.04 ( No.124 ) でやったね。どんなポインタでも……あ、
そっかそれならどんな型でも使えるね』
「そういうこと。使用例を含めて、まとめて見てみようか」
// 配列の要素にする構造体。
struct SORT_DATA
{
int m_iIndex;
CString m_cDataStr;
};
// p_pL > p_pR なら true を、
// それ以外は false を返すようにしてください。
bool CompareToForSORT_DATA( void *p_pL, void *p_pR )
{
SORT_DATA *pstSortDataL = (SORT_DATA *)p_pL;
SORT_DATA *pstSortDataR = (SORT_DATA *)p_pR;
// 数値で比較します。
if( pstSortDataL->m_iIndex > pstSortDataR->m_iIndex )
{
return true;
}
else if(
( pstSortDataL->m_iIndex == pstSortDataR->m_iIndex ) &&
( pstSortDataL->m_cDataStr > pstSortDataR->m_cDataStr )
)
{
// 数値は一致。
// 文字列は左の方が大きいです。
return true;
}
return false;
}
void DoBubbleSortToCPtrArray( CPtrArray &p_rcPtrAry )
{
// 「入れ替え先」のループです。
for( int iOut = 0; iOut < p_rcPtrAry.GetSize() - 1; iOut++ )
{
// 最後から先頭方向へのループです。
// ただし「入れ替え先」までです。
for( int iIn = p_rcPtrAry.GetSize() - 1; iOut < iIn; iIn-- )
{
if( CompareToForSORT_DATA
( p_rcPtrAry.GetAt( iIn - 1 )
, p_rcPtrAry.GetAt( iIn )
)
== true )
{
// 前の方が大きいので入れ替えます。
void *pcTemp = p_rcPtrAry.GetAt( iIn );
p_rcPtrAry.SetAt( iIn, p_rcPtrAry.GetAt( iIn - 1 ) );
p_rcPtrAry.SetAt( iIn - 1, pcTemp );
}
}
}
}
// 使用例。
void Use_DoBubbleSortToCPtrArray()
{
CPtrArray cPtrAry;
SORT_DATA *pstSortData;
pstSortData = new SORT_DATA;
pstSortData->m_iIndex = 9;
pstSortData->m_cDataStr = "EEE";
cPtrAry.Add( pstSortData );
pstSortData = new SORT_DATA;
pstSortData->m_iIndex = 3;
pstSortData->m_cDataStr = "DDD";
cPtrAry.Add( pstSortData );
pstSortData = new SORT_DATA;
pstSortData->m_iIndex = 1;
pstSortData->m_cDataStr = "CCC";
cPtrAry.Add( pstSortData );
pstSortData = new SORT_DATA;
pstSortData->m_iIndex = 3;
pstSortData->m_cDataStr = "BBB";
cPtrAry.Add( pstSortData );
pstSortData = new SORT_DATA;
pstSortData->m_iIndex = 5;
pstSortData->m_cDataStr = "AAA";
cPtrAry.Add( pstSortData );
// ソートします。
DoBubbleSortToCPtrArray( cPtrAry );
for( int iF1 = 0; iF1 < cPtrAry.GetSize(); ++iF1 )
{
pstSortData = (SORT_DATA *)cPtrAry.GetAt( iF1 );
TRACE
( "%d, %s\n"
, pstSortData->m_iIndex
, pstSortData->m_cDataStr
);
delete pstSortData;
}
}
/*
実行結果:
1, CCC
3, BBB
3, DDD
5, AAA
9, EEE
*/
「まず使用例から見てもらおうかな」
pstSortData = new SORT_DATA;
pstSortData->m_iIndex = 9;
pstSortData->m_cDataStr = "EEE";
cPtrAry.Add( pstSortData );
『構造体 new して、そこにデータ入れて、んで CStringArray みたく
Add() 、だよね』
「そう。基本的にコレクションクラスのメンバ関数はどれも同じ。だから、
ひとつ憶えれば他にも使えるかな」
『 GetSize() とか GetAt() 、 SetAt() もそうだね。それにしても……
やっぱり new しなきゃいけないんだ』
「ポインタを扱うクラスだからね、それは避けられないかな」
『ちょっと面倒かも……』
「次にソート本体」
『最初の for ふたつは前回と同じね。比較するところは……あ、関数がか
なり変わってる』
「今回は、構造体のポインタをまるごと受け取るようにしました」
『なんかかなり違う……』
bool CompareToForSORT_DATA( void *p_pL, void *p_pR )
『って、いきなり引数 void ポインタだし』
「これは意味があるんです。 DoBubbleSortToCPtrArray() を見てみて。
SORT_DATA や、そのメンバの m_iIndex や m_cDataStr って出てないで
しょ」
『そういえば』
「つまり、 DoBubbleSortToCPtrArray() はソート対象の各要素がどんな型
でも使えるってこと」
『あ…… void ポインタで扱ってて、キャストしたり、その中身にアクセス
したりしてないから?』
「そういうことで、そのアクセスしたりとかキャストしたりとかを、比較関
数、つまり CompareToForSORT_DATA() でしてるんです」
『……それに意味が?』
「 CompareToForSORT_DATA() を変えるだけで、どんな型でもOKでしょ」
『あ、なるほど』
「これはあと何回かしたら教える qsort() っていう関数のところで出てく
るから、ちょっと頭の隅に憶えておいて」
『はーい』
「では比較関数について。今回ちょっと違う比較方法にしてみました」
『2段階に比較してるね』
// 数値で比較します。
if( pstSortDataL->m_iIndex > pstSortDataR->m_iIndex )
{
return true;
}
else if(
( pstSortDataL->m_iIndex == pstSortDataR->m_iIndex ) &&
( pstSortDataL->m_cDataStr > pstSortDataR->m_cDataStr )
)
{
// 数値は一致。
// 文字列は左の方が大きいです。
return true;
}
return false;
}
『 m_iIndex と m_cDataStr の両方を比較してるんだ』
「まず m_iIndex で比較して、同じなら m_cDataStr で比較。検索結果もそ
うなってるでしょ」
『 3 のところ、 BBB が上に来てる』
「安定ソートだから、もし m_cDataStr で比較していなかったら、元の順番
通り DDD が上に来るはずだからね」
『こういうソート方法もあるってことね』
「この辺は実際に使いたい機能によって色々変えてみてください」
/*
Preview Next Story!
*/
『なんか今回は実用的!』
「構造体で可変長、っていうのはよくあるからね」
『こういう実用的なのばっかりだといいなー』
「う”」
『なによ、う”って』
「というわけで次回」
< Version 13.14 リストのしくみ >
『につづく!』
「このリスト、ソートには向かないんです……」
『さっそくかい』