方法 : タイプ セーフなコレクションを作成する
この記事では、独自のデータ型に応じてタイプ セーフなコレクションを作成する方法について説明します。 取り上げるトピックは次のとおりです。
Microsoft Foundation Class ライブラリには、C++ テンプレートに基づく定義済みのタイプ セーフなコレクションが用意されています。 これらのクラスはテンプレートであるため、型キャストや、非テンプレート クラスを使用するために必要なその他の追加作業を行わずに、タイプ セーフで、使いやすさを提供するのに役立ちます。 MFC サンプル COLLECT は、MFC アプリケーションでのテンプレート ベースのコレクション クラスを使用する方法を示しています。 一般に、新しいコレクション コードを記述するときは常にこれらのクラスを使用します。
タイプ セーフにテンプレート ベースのクラスを使用する
テンプレート ベースのクラスを使用するには
コレクション クラス型の変数を宣言します。 次に例を示します。
CList<int, int> m_intList;コレクション オブジェクトのメンバー関数を呼び出します。 次に例を示します。
m_intList.AddTail(100); m_intList.RemoveAll();必要に応じて、ヘルパー関数と SerializeElements を実装します。 これらの関数の実装の詳細については、「ヘルパー関数の実装」を参照してください。
この例では、整数のリストの宣言を示します。 手順 1 の最初のパラメーターは、リストの要素として格納されるデータの種類です。 2 番目のパラメーターは、コレクション クラスのメンバー関数 (Add や GetAt など) との間でデータをやり取りする方法を指定します。
ヘルパー関数を実装する
テンプレート ベースのコレクション クラス CArray、CList。および CMap は、5 つのグローバル ヘルパー関数を使用します。これらは、派生コレクション クラスに応じて、必要に応じてカスタマイズできます。 これらのヘルパー関数の詳細については、「MFC リファレンス」の「コレクション クラス ヘルパー」を参照してください。 テンプレート ベースのコレクション クラスを使用するときは、ほとんどの場合、シリアル化関数の実装が必要です。
シリアル化要素
CArray、CList、および CMap の各クラスは SerializeElements を呼び出して、コレクションの要素をアーカイブに格納するか、アーカイブから読み取ります。
SerializeElements ヘルパー関数の既定の実装では、オブジェクトがアーカイブに格納されているか、アーカイブから取得されているかに応じて、オブジェクトからアーカイブへのビットごとの書き込み、またはアーカイブからオブジェクトへのビットごとの読み取りが行われます。 このアクションが適切でない場合は、SerializeElements をオーバーライドします。
コレクションが CObject から派生したオブジェクトを格納し、その IMPLEMENT_SERIAL マクロをコレクション要素クラスの実装で使用する場合は、CArchive と CObject に組み込まれているシリアル化機能を利用できます。
CArray< CPerson, CPerson& > personArray;
template <> void AFXAPI SerializeElements <CPerson>(CArchive& ar,
CPerson* pNewPersons, INT_PTR nCount)
{
for (int i = 0; i < nCount; i++, pNewPersons++)
{
// Serialize each CPerson object
pNewPersons->Serialize(ar);
}
}
CArchive のオーバーロードされた挿入演算子は、CPerson オブジェクトごとに CObject::Serialize (または、この関数のオーバーライド) を呼び出します。
非テンプレート コレクション クラスを使用する
MFC では、MFC バージョン1.0 で導入されたコレクション クラスもサポートされています。 これらのクラスは、テンプレートに基づいていません。 サポートされている型 CObject*、UINT、DWORD、および CString のデータを格納するために使用できます。 これらの定義済みコレクション (CObList など) を使用して、CObject から派生したオブジェクトのコレクションを保持できます。 MFC には、UINT や void ポインター (void*) などのプリミティブ型を保持するための、他の定義済みコレクションも用意されています。 ただし、一般的には、より具体的なクラスとその派生クラスのオブジェクトを保持するために、独自のタイプ セーフなコレクションを定義すると便利です。 テンプレートに基づいていないコレクション クラスを使用してこれを行う場合は、テンプレート ベースのクラスを使用する場合よりも作業が多くなります。
非テンプレート コレクションでタイプ セーフなコレクションを作成するには、次の 2 つの方法があります。
必要に応じて型キャストを使用して、非テンプレートコレクションを使用する。 これは、より簡単な方法です。
非テンプレートのタイプ セーフ コレクションから派生し、拡張する。
型キャストを使用して、非テンプレート コレクションを使用するには
CWordArrayなどの非テンプレート クラスの 1 つを直接使用します。たとえば、
CWordArrayを作成し、32 ビット値を追加してから取得できます。 これ以上、行うことはありません。 定義済みの機能を使用するだけです。また、定義済みのコレクション (
CObListなど) を使用して、CObjectから派生したオブジェクトを保持することもできます。CObListコレクションは、CObjectへのポインターを保持するように定義されます。 リストからオブジェクトを取得する場合、CObList関数がCObjectへのポインターを返すため、結果を適切な型にキャストする必要が生じる場合があります。 たとえば、CPersonオブジェクトをCObListコレクションに格納する場合は、取得した要素をCPersonオブジェクトへのポインターにキャストする必要があります。 次の例では、CObListコレクションを使用してCPersonオブジェクトを保持します。CPerson* p1 = new CPerson(); CObList myList; myList.AddHead(p1); // No cast needed CPerson* p2 = (CPerson*)myList.GetHead();このように定義済みのコレクション型を使用し、必要に応じてキャストする方法は、コレクションのニーズの多くに適している可能性があります。 さらに機能またはタイプ セーフが必要な場合は、テンプレート ベースのクラスを使用するか、次の手順に従います。
非テンプレートのタイプ セーフ コレクションから派生し、拡張するには
定義済みの非テンプレート クラスの 1 つから独自のコレクション クラスを派生させます。
クラスを派生させると、タイプ セーフなラッパー関数を追加して、既存の関数にタイプ セーフなインターフェイスを提供できます。
たとえば、
CPersonオブジェクトを保持するためにCObListからリストを派生させる場合は、次に示すように、ラッパー関数AddHeadPersonとGetHeadPersonを追加できます。class CPersonList : public CObList { public: void AddHeadPerson(CPerson* person) { AddHead(person); } const CPerson* GetHeadPerson() { return (CPerson*)GetHead(); } };これらのラッパー関数は、派生リストから
CPersonオブジェクトを追加および取得するためのタイプ セーフな方法を提供します。GetHeadPerson関数の場合は、単純に型キャストをカプセル化するだけであることがわかります。また、既存の機能をタイプ セーフ ラッパーに単にラップするのではなく、コレクションの機能を拡張する新しい関数を定義して、新しい機能を追加することもできます。 たとえば、「CObject コレクションの全オブジェクトの削除」という記事では、一覧内に含まれているすべてのオブジェクトを削除する関数について説明されています。 この関数は、メンバー関数として派生クラスに追加できます。