MFC中的集合类1

 STL中的集合类数组、列表、关联,MFC中也有相似的类,下面列出MFC中的一些使用方法。

实际上集合类就是数据结构中的顺序存储结构和链表存储结构。它的优点就是建立这样的存储结构简单,并且把相关的操作集中成函数,方便用户的调用。比如顺序存储用到数组,如果要在数组中的固定位置添加一项,普通的方法就是要用一个for循环,有点烦琐。而在集合类中只要用一个add函数就完成了,相对简单一点。

 

数据结构是软件设计中的一个重要组成部分。因此我们有必要搞清楚集合类的相关问题。

 

1.3种类型

集合类中有3种大的类型:

(1)         Array: 数组,可以动态的改变大小,有索引值和最大下标等。

(2)         List:双向链表,无索引,链表有头尾,插入元素要比数组快。

(3)         Map:是一种映射,俗名“字典”,是一种关联式数组。(在此不做讨论)

 

2.各自特点:

类型

是否有序

插入元素速度

搜索元素速度

索引

Array

List

 

3.MFC中的集合类

是否使用模板

是否支持串行化

是否支持倾印

CArray

CTypedPtrArray

可能

CByteArray

CDWordArray

CObArray

CPtrArray

CStringArray

CWordArray

CUIntArray

CList

CTypedPtrList

可能

COblist

CStringList

 

 

4.几点说明

(1) 有些集合类是从c++模板支持的,如CArray,CList,使用时必须指出所要收集对象的类型,比如int,char,CPoint等,可以参考一下c++模板的知识。

 

(2)在表中有2个“可能“,因为CTypedPtrArray,CTypedPtrList这些类在使用时要指定基类,如果基类可以串行化,那么它就可以串行化。

 

(3)在深入浅出MFC中,作者说CUIntArray是可以串行化的,但我在做项目时证明它是不可以串行化的,希望读者注意

如一个对象类:

        Void  CStudent::Serialize(CArchive &ar)

 {

                   ……

        m_array.Serialize(ar);//这里m_array是CUIntArray的对象

     }

可是运行后发现并没有成功。因此只好采用for循环:

        Void  CStudent::Serialize(CArchive &ar)

   {

                   If(ar.IsStoring( ))//存储

                   {

                            ar<<m_array.GetSize();

                            for(int i=0;i<m_array.GetSize();i++)

               ar<<m_array.GetAt(i)

       }

       …..//读取略

}

 

5.常用函数举例

(1) 数组

         如int 数组:

                  CArray<int,int>  m_intArray;

                   m_intArray.Add(15);   // 添加一个元素

                   CArray<CPoint,CPoint> pArray;

                   pArray.Add(CPoint(10,10));

 

l        添加元素

注意,此时开始并没有分配数组的存储空间,但是add可以动态分配空间。如果可以预计数组大小,可以先用SetSize()来分配空间,因为如果频繁使用add,会产生内存碎片。SetSize可以增加数组元素,也可以减少,但是在减少时,并不会自动缩小保存数组数据的缓冲区,还是先调用removeAt先把元素删掉。

 

推荐使用:SetAtGrow(int index,ARG_TYPE newElement ),它与Add相比,就是可以利用它修改数组中的数组;而如果用add,那么必须先RemoveAll

 

l        获得元素个数和最大下标

GetSize():可以返回数组中元素的个数。

GetUpperBound():返回数组中的最大下标,一般加1就和GetSize()相等。

 

l        获得成员值

一般可以用GetAt(),有时可能要强制类型转化。如:

CObArray  array;

  Cline *pline=new Cline(100,100,200,200);//Cline为直线类,用起点和终点坐标初始化

 array.Add(pline);//此处存储的只是一个地址

 Cline *p=(Cline*)array.GetAt(0);//必须强制类型转换

 

注意这里必须使用new动态创建内存空间。如果是局部变量,等到函数结束,就不能够再通过数组来引用这块内存了,因为已经析构。

当然也可以不用类型转化。此时可以用集合类CTypedPtrArray,例如


  CTypedPtrArray<CobArray,Cline*) array ;//表示array是CobArray对象,专门存储Cline*指针

  Cline *pline=new Cline(100,100,200,200);//Cline为直线类,用起点和终点坐标初始化

  array.Add(pline);

  Cline *p=array.GetAt(0);//不用强制类型转换

 

l        修改成员值

 

一般可以使用函数SetAt(),但是在修改之前,这个元素的内存空间必须已经分配,比如下面这样写是错误的:

  CUIntArray  Array;

  Array.SetAt(0,10) ;//想把第一项修改为10;

可以这样写来修改元素的值:

   CUIntArray  Array;

  Array.Add(5) ;

  Array.SetAt(0,10) ;//把第一项5修改为10;

另外用数组成员引用符号[]来表示也可以来修改或者是获得元素值。

   CUIntArray  Array;

  Array.Add(5) ;

Array[0]=5 ;//把第一项5修改为10;

同样 这样写是错误的:

  CUIntArray  Array

  Array.Add(5) ;

  Array.GetAt(0)=5 ;//想把第一项5修改为10;

     删除元素

RemoveAt():删除一个元素,删除后,数组中的索引号会自动改变。

RemoveAll():删除所有元素。

注意如果要同时删除几个元素,必须从后面删除起。

比如:

CUIntArray  Array;

    Array.Add(5) ;

Array.Add(10);

Array.Add(13);

Array.RemoveAt(0);

Array.RemoveAt(1);

本来是要删除第1个元素和第二个元素,但结果却是把第一个元素和第三个元素删除了,因为当调用Array.RemoveAt(0);删除第一个元素后,索引号开始变化,元素10成为索引要从1变为0,而元素13的索引号从2变为1。解决这个问题可以从后面开始删除:

CUIntArray  Array;

    Array.Add(5) ;

Array.Add(10);

Array.Add(13);

Array.RemoveAt(1);

Array.RemoveAt(0);

只是改变了顺序,效果却大不相同哦!

 

 

 

(2) 链表

 

l        添加成员

Clist<int,int> m_intlist ;

 m_intlist.AddTail(36) ;//在尾部添加

m_intlist.AddHead(34) ;//在头部添加

 

l        遍历

POSITION pos=m_intlist.GetHeadPosition() ;

While(pos !=NULL)

{

           int i=m_intlist.GetNext(pos) ;

}//数组中有索引号,要方便一些。

 

其他用法数组差不多,不作介绍。

 

 

6. 动态创建的含义

 

举例说明:

还是有个直线类,现在要串行化保存。

 

         添加元素

Cline *line =new Cline(100,100,200,200);

m_array.Add(line); //CObArray m_array;  类中的成员变量

 

          

在文档类中保存和读取

 Void CMyDocument::Serialize(CArchive & ar)

{

         m_array.Serialize(ar);

}

 

 

实际上在m_array.Serialize(ar);的内部实现用到了for循环,一个一个元素的存储和读取的。

前面已经说过line必须是动态分配空间的,所以存储是可以理解的。但是如果关闭这个程序,所有内存全部释放,此时再次运行程序,打开文件,肯定会调用m_array.Serialize(ar);,在内部又是采用for循环一个一个读取,但是这里并我并没有动态分配空间,它从磁盘读取的内容(Cline)到底存在哪里啊?

 

在深入浅出MFC中给出了很好的说明。在调用CArchive中这个重载符号”>>”,也就是读取时,内部会再次调用一系列的函数,有一个是CreateObject(),它的代码就是

CObject *Cline ::CreateObject()

{

return new Cline;

}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值