围绕微软提供的collect示例代码进行说明。可在X:/Microsoft Visual Studio 9.0/Samples/2052/C++/MFC/advanced/collect下找到该程序。
首先说说collect的框架。collect是一个SDI风格的窗口程序,“Example”菜单提供了9种不同的集合类示例,点击某一个集合类,可以切换到该集合类的视图窗口下,其中每个集合类都包括这些操作:
添加新元素。
将新元素插入到列表中间。
搜索元素(通过在对话框的列表框中单击该元素的项)。
通过输入搜索词并单击“Find”在映射中搜索项。
更新元素的值。
移除元素。
移除集合中的所有元素。
串行化(通过在“文件”菜单上单击“保存”可以保存对所有示例的更改,通过在“文件”菜单上单击“打开”则可以读回它们。)
在类视图中,将9种集合类的视图分别绑定一个类(派生于CFormView),数据处理统统放在CCollectDoc类中。
通过以上操作的学习,可以对集合类有个深入的了解。
collect阐述了标志*号的集合类。
集合形状 |
非基于模板的 |
基于模板的简单元素 |
基于模板的 typeSafe 指针 |
---|---|---|---|
列表 |
CStringList* |
CList* |
CTypedPtrList |
|
CObList |
|
(属于指针)* |
|
CPtrList |
|
CTypedPtrList |
|
|
|
(属于 CObject) |
数组 |
CByteArray |
CArray* |
CTypedPtrArray |
|
CUIntArray |
|
(属于指针) |
|
CWordArray |
|
|
|
CDWordArray * |
|
CTypedPtrArray |
|
CStringArray |
|
(属于 CObject)* |
|
CPtrArray |
|
|
|
CObArray |
|
|
映射 |
CMapWordToPtr |
CMap* |
CTypedPtrMap* |
|
CMapWordToOb |
|
|
|
CMapStringToString* |
|
|
|
CMapStringToPtr |
|
|
|
CMapStringToOb |
|
|
|
CMapPtrToWord |
|
|
|
CMapPtrToPtr |
|
|
对于上表中,集合类还可以分为三个类型
1、非基于模板的:又叫具体类,就是MFC已经预置了元素类型,不需要自定义。
2、 基于模板的简单元素:又叫模板类,需要自己定义元素类型,元素的类型为对象实体。
3、基于模板的 typeSafe 指针:带有typesafe特性,元素类型为自己指定的类对象指针。
注:typesafe特性就是“Provides a type-safe "wrapper"”
意指提供一个类型安全的“包装”
因为定义时需要明确指出指针的类型,所以只能存储该类型的指针,不会有其它乱七八糟的指针存储进去。而很多指针类型的容器是允许保存任何类型的指针,常用void* 。
这篇主要说说数组类型。
先说说CStringList.
CStringList集合中的元素类型为CString,可以理解为以CString元素组成的链表。
它的操作包括:
1、AddTail:在链表的尾部添加元素。
2、InsertBefore:在指定的索引位置前插入元素。
3、SetAt:在指定的索引位置设置指定的元素。
4、RemoveAt:删除指定的索引位置的元素。
5、RemoveAll:清除集合中所有的元素。
6、串行化:可直接调用CStringList的Serialize进行串行化操作。
7、Find或FindIndex:通过元素值或元素索引来搜索元素。返回POSITION类型。
以上操作全部在CCollectDoc中处理。
collect中还牵涉到一些控件的操作,包括列表框、编辑框、按钮。以下一一说明。这些说明对后面的几个类也同样适用。
以CStringList的视图为例:
1、编辑框IDC_ELEMENT绑定了成员函数m_strElement,以方便元素录入。
2、列表框IDC_LIST绑定了成员函数m_ctlList,以方便控件操作。
3、各按钮为集合操作定义
看一个例子:
void CStringListView::OnAdd()
{
if (UpdateData() != TRUE)
return;
GetDocument()->m_stringList.AddTail(m_strElement);
m_ctlList.AddString(m_strElement);
}
这是添加元素按钮的响应函数。
1、UpdateData() :默认的参数是TRUE,作用是将编辑框输入的值,更新到m_strElement中。如参数为FALSE,则是将m_strElement的值更新到编辑框上,在OnSelChangeList()函数中用到
2、GetDocument():取得CCollectDoc的指针。
3、m_stringList.AddTail():插入m_strElement到m_stringList集合末尾。
4、m_ctlList.AddString():插入m_strElement到列表框中。
再说说其他的列表框操作:
1、m_ctlList.GetCurSel():取得当前在列表框中选择的元素的位置。若列表框为空或未选择,返回LB_ERR。
2、m_ctlList.GetText():取得参数1索引的元素,存入参数2中,并将索引位置设定为下一个位置。
3、m_ctlList.InsertString():在参数1指定的位置前插入参数2。
4、m_ctlList.DeleteString():删除参数1索引指定的元素。返回剩余元素的数量int。
5、m_ctlList.ResetContent():删除列表框中所有的元素。
下面说说CTypedPtrList集合类。
这个类在示例中用于存储类对象的指针。原型为:
template< class BASE_CLASS, class TYPE >
class CTypedPtrList : public BASE_CLASS
其中 BASE_CLASS只能为CObList or CPtrList,class TYPE为类对象的指针。
collect示例中,使用CTypedPtrListView类(继承于CFormView)显示此类的视图,数据处理全部放在CCollectDoc中。
CCollectDoc中的定义:CTypedPtrList<CPtrList, CMyStruct*>
此例中首先定义了CMyStruct类(无基类),有三个成员函数int,float,CString。
然后需要将CMyStruct类对象的指针(CMyStruct*)存储到CTypedPtrList中。
最后做相关操作。
相关操作主要有:
1、AddTail:向链表末尾添加元素。此处需要new一个CMyStruct对象,后期remove操作时,需delete这个对象。
2、InsertBefore:在指定的索引位置前插入元素。
3、RemoveAt:删除指定的索引位置的元素。
4、RemoveAll:清除集合中所有的元素。
5、Find:Find或FindIndex:通过元素值或元素索引来搜索元素。返回POSITION类型。
注意:移除操作除了将集合类中将指针移除,同时也要用delete对CMyStruct对象进行释放。
如下代码演示了这个过程:
POSITION pos = mystructList.GetHeadPosition();//获取集合类中的第一个元素位置
while (pos != NULL)
{
delete mystructList.GetNext(pos);//循环取出元素进行释放(注意这时释放的是指针指向的区域,而非指针本身)
}
mystructList.RemoveAll();//移除存放在集合类中的指针(释放的是指针本身)
最后说说CList
这个类在一个模板类,示例中被定义为CList<int,int> m_intList,也就是一个int类型元素的集合。
第一个参数表示链表中节点的数据类型为int,第二个参数表示操作时,传递给链表的参数类型必须为int。
几个操作与CStringList一致。
说了三个集合类,做一个阶段性的总结。
首先以上阐述的三个类,都是以链表的形式实现的,也就是说,他们在做插入和删除元素时,比较高效。
但在随机访问数据的能力上,链表需通过Find函数搜索元素位置,而后面要阐述的数组则直接通过下标访问,数组速度更快。
三个类的基本操作类似,CTypedPtrList略微复杂,因链表中存储的是指针,在替换元素时,直接利用指针操作;在清除元素时,应注意释放指针本体和指针指向的区域。
下一章进入数组类型集合类的阐述。