この記事では、独自のデータ型に対してタイプ セーフなコレクションを作成する方法について説明します。 ここでは、次の内容について説明します。
Microsoft Foundation クラス ライブラリには、C++ テンプレートに基づく定義済みのタイプ セーフ コレクションが用意されています。 これらのクラスはテンプレートであるため、この目的で非テンプレート クラスを使用する際に、型キャストやその他の余分な作業を行わずに、型の安全性と使いやすさを実現できます。 MFC サンプル COLLECT は、MFC アプリケーションでのテンプレート ベースのコレクション クラスの使用を示しています。 一般に、これらのクラスは、新しいコレクション コードを記述するたびに使用します。
タイプ セーフに Template-Based クラスを使用する
テンプレート ベースのクラスを使用するには
コレクション クラス型の変数を宣言します。 例えば次が挙げられます。
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);
}
}
各CPerson オブジェクトのCArchive呼び出しCObject::Serialize (またはその関数のオーバーライド) のオーバーロードされた挿入演算子。
非テンプレート コレクション クラスの使用
MFC では、MFC バージョン 1.0 で導入されたコレクション クラスもサポートされています。 これらのクラスはテンプレートに基づいていません。 これらは、サポートされている型 CObject*、 UINT、 DWORD、および CStringのデータを格納するために使用できます。 これらの定義済みのコレクション ( CObList など) を使用して、 CObjectから派生したオブジェクトのコレクションを保持できます。 MFC には、 UINT ポインターや void ポインター (void*) などのプリミティブ型を保持する定義済みの他のコレクションも用意されています。 ただし、一般に、より具体的なクラスとその派生クラスのオブジェクトを保持するために、独自の型セーフ コレクションを定義すると便利です。 テンプレートに基づいていないコレクション クラスでこれを行う方が、テンプレート ベースのクラスを使用するよりも作業が多い点に注意してください。
非テンプレート コレクションを使用してタイプ セーフなコレクションを作成するには、次の 2 つの方法があります。
必要に応じて型キャストを使用して、非テンプレート コレクションを使用します。 これはより簡単なアプローチです。
非テンプレート型セーフ コレクションから派生し、拡張します。
型キャストで非テンプレート コレクションを使用するには
CWordArrayなどの非テンプレート クラスのいずれかを直接使用します。たとえば、
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 コレクション内のすべてのオブジェクトの削除 に関する記事では、リストに含まれるすべてのオブジェクトを削除する関数について説明します。 この関数は、メンバー関数として派生クラスに追加できます。