本文解释 MFC 3.0 版及更高版本中类型安全、基于模板的集合类。使用这些模板创建类型安全集合更为方便,并且提供了比使用不基于模板的集合类更高的类型安全。
MFC 预定义了两类基于模板的集合:
- 简单数组、列表和映射类
CArray、CList、CMap
- 类型化指针的数组、列表和映射
CTypedPtrArray、CTypedPtrList、CTypedPtrMap
简单集合类都是从 CObject 类派生的,所以继承了 CObject 的序列化、动态创建以及其他属性。类型指针集合类要求指定派生自的类,该类必须是 MFC 预定义的非模板指针集合之一,如 CPtrList 或 CPtrArray。新的集合类从指定的基类继承,并且新类的成员函数对基类成员使用封装调用以强制类型安全。
有关 C++ 模板的更多信息,请参见 C++ Language Reference 中的模板。
使用简单数组、列表和映射模板
若要使用简单集合模板,需要知道可以在这些集合中存储的数据类型以及集合声明中所使用的参数类型。
简单数组和列表的用法
简单的数组类 CArray 和列表类 CList 采用两个参数:TYPE 和 ARG_TYPE。这些类可以存储任何在 TYPE 参数中指定的数据类型:
- 基本 C++ 数据类型,如 int、char 和 float
- C++ 结构和类
- 定义的其他类型
考虑到方便性和效率,可以使用 ARG_TYPE 参数来指定函数参数的类型。通常情况下,将 ARG_TYPE 指定为对 TYPE 参数中命名类型的引用。例如:
CArray<int, int> myArray; CList<CPerson, CPerson&> myList;
第一个示例声明了一个包含多个 int 的数组集合 myArray
。第二个示例声明了一个存储 CPerson
对象的列表集合 myList
。集合类的某些成员函数采用其类型由 ARG_TYPE 模板参数指定的参数。例如,CArray 类的 Add 成员函数采用 ARG_TYPE 参数:
CArray<CPerson, CPerson&> myArray; CPerson person; myArray->Add( person );
简单映射的用法
简单映射类 CMap 采用四个参数:KEY、ARG_KEY、VALUE 和 ARG_VALUE。与数组类和列表类一样,映射类也可以存储任何数据类型。但映射不像数组和列表那样索引和排序它们存储的数据,而是将键与值相关联:通过指定值的关联键访问存储在映射中的值。KEY 参数指定键的数据类型,该键用于访问存储在映射中的数据。如果 KEY 的类型是结构或类,则 ARG_KEY 参数通常是对 KEY 中指定类型的引用。VALUE 参数指定存储在映射中的项类型。如果 ARG_VALUE 的类型是结构或类,则 ARG_VALUE 参数通常是对 VALUE 中指定类型的引用。例如:
CMap< int, int, MY_STRUCT, MY_STRUCT& > myMap1; CMap< CString, LPCSTR, CPerson, CPerson& > myMap2;
第一个示例存储 MY_STRUCT
值,通过 int 键访问这些值,并通过引用返回访问的 MY_STRUCT
项。第二个示例存储 CPerson
值,通过 CString 键访问这些值,并返回对访问项的引用。该示例可以表示简单的通讯簿,可按姓氏在其中查找人员。
因为 KEY 参数的类型是 CString 且 KEY_TYPE 参数的类型是 LPCSTR,所以键作为 CString 类型的项存储在映射中,但通过 LPCSTR 类型的指针在 SetAt 等函数中被引用。例如:
CMap< CString, LPCSTR, CPerson, CPerson& > myMap2; CPerson person; LPCSTR lpstrName = "Jones"; myMap2->SetAt( lpstrName, person );
使用类型指针集合模板
若要使用类型指针集合模板,需要知道可以在这些集合中存储的数据类型以及集合声明中所使用的参数类型。
类型指针数组和列表的用法
类型指针数组类 CTypedPtrArray 和列表类 CTypedPtrList 采用两个参数:BASE_CLASS 和 TYPE。这些类可以存储任何在 TYPE 参数中指定的数据类型。它们从存储指针的某个非模板集合类中派生,在 BASE_CLASS 中指定该基类。对于数组,使用 CObArray 或 CPtrArray。对于列表,使用 CObList 或 CPtrList。
实际上,当基于某个类(比如 CObList)声明集合时,新类不仅继承其基类的成员,还声明若干其他的类型安全成员函数和运算符,这些函数和运算符通过封装对基类成员的调用来提供类型安全。这些封装管理所有必需的类型转换。例如:
CTypedPtrArray<CObArray, CPerson*> myArray; CTypedPtrList<CPtrList, MY_STRUCT*> myList;
第一个示例声明了从 CObArray 派生的类型指针数组 myArray
。该数组存储并返回指向 CPerson
对象(其中 CPerson
是从 CObject 派生的类)的指针。可以调用任何 CObArray 成员函数,或者可以调用新的类型安全函数 GetAt 和 ElementAt 或使用类型安全运算符 [ ]。
第二个示例声明了从 CPtrList 派生的类型指针列表 myList
。该列表存储并返回指向 MY_STRUCT
对象的指针。基于 CPtrList 的类用于存储指向不是派生自 CObject 的对象的指针。CTypedPtrList 有若干个类型安全成员函数:GetHead、GetTail、RemoveHead、RemoveTail、GetNext、GetPrev 和 GetAt。
类型指针映射的用法
类型指针映射类 CTypedPtrMap 采用三个参数:BASE_CLASS、KEY 和 VALUE。BASE_CLASS 参数指定从中派生新类的基类:CMapPtrToWord、CMapPtrToPtr、CMapStringToPtr、CMapWordToPtr、CMapStringToOb 等。KEY 类似于 CMap 中的 KEY:指定用于查找的键的类型。VALUE 类似于 CMap 中的 VALUE:指定存储在映射中的对象类型。例如:
CTypedPtrMap<CMapPtrToPtr, CString, MY_STRUCT*> myPtrMap; CTypedPtrMap<CMapStringToOb, CString, CMyObject*> myObjectMap;
第一个示例是基于 CMapPtrToPtr 的映射,它使用映射到指向 MY_STRUCT
的指针的 CString 键。可通过调用类型安全的 Lookup 成员函数来查找存储的指针。可以使用 [ ] 运算符查找存储的指针;如果没有找到,则添加它。并且可以使用类型安全的 GetNextAssoc 函数迭代映射。也可以调用 CMapPtrToPtr 类的其他成员函数。
第二个示例是基于 CMapStringToOb 的映射,它使用映射到指向 CMyObject
对象的存储指针的字符串键。可以使用在前面的段落中描述的同一类型安全成员,或调用 CMapStringToOb 类的成员。
注意 如果为 VALUE 参数指定 class 或 struct 类型,而不是指定指向该类型的指针或对该类型的引用,则类或结构必须具有复制构造函数。
有关更多信息,请参见如何创建类型安全集合。