方法 : タイプ セーフなコレクションを作成する
ここでは、独自のデータ型を格納するタイプ セーフなコレクションの作成方法について説明します。 ここでは、次の内容について説明します。
テンプレート ベースのクラスによるタイプ セーフの使用
ヘルパー関数の実装
非テンプレート コレクション クラスの使用
MFC には、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 1.0 で導入されたコレクション クラスもサポートされています。 このようなクラスは、テンプレート ベースではありません。 非テンプレート コレクション クラスには、CObject*、UINT、DWORD、CString の各データ型を格納できます。 これらの定義済みコレクション (CObList など) には、CObject クラスの派生オブジェクトを格納できます。 MFC には、UINT や void 型ポインター (void*) などのプリミティブな型のオブジェクトを格納するための定義済みコレクションもあります。 ただし、通常は、タイプ セーフな独自の型を定義した方が、固有のクラスとその派生クラスのオブジェクトを格納しやすくなります。 このようなオブジェクトを非テンプレート コレクション クラスに格納すると、テンプレート ベースのクラスより余分な作業が必要になります。
非テンプレート コレクションでタイプ セーフなコレクションを作成するには、次のどちらかの方法を使います。
非テンプレート コレクションを直接使用し、必要に応じて型をキャストします。 これは簡易手順です。
タイプ セーフな非テンプレート コレクションから派生し、機能を拡張します。
非テンプレート コレクションと型キャストを使用するには
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();
上のように定義済みのコレクションを使用し、必要に応じてキャストするという手法は、多くの場合に十分対応できます。 さらに機能が必要な場合、またはより確実に型を保証するには、次の手順に従うか、テンプレート ベースのクラスを使ってください。
タイプ セーフな非テンプレート コレクションから派生し、機能を拡張するには
定義済みの非テンプレート クラスからカスタム クラスを派生します。
クラスを派生するときに、タイプ セーフなラッパー関数を追加すると、既存の関数に対するタイプ セーフなインターフェイスになります。
たとえば、CPerson オブジェクトを格納するリストを CObList クラスから派生するときは、次のようにラッパー関数 AddHeadPerson と GetHeadPerson を定義します。
class CPersonList : public CObList { public: void AddHeadPerson( CPerson* person ) {AddHead( person );} const CPerson* GetHeadPerson() {return (CPerson*)GetHead();} };
ラッパー関数を使用すると、派生リストへの CPerson オブジェクトの追加時およびリストからの取得時に型が保証されます。 GetHeadPerson 関数の場合は、型キャストをカプセル化するだけで十分です。
単に既存の関数をタイプ セーフなラッパー関数でラップするだけではなく、コレクションの機能を拡張する新しい関数を定義してコレクションに機能を追加することもできます。 たとえば、「CObject コレクションの全オブジェクトの削除」では、リスト内のすべてのオブジェクトを削除する関数について説明しています。 この関数は、派生クラスにメンバー関数として追加できます。