MFC中的集合類1

來源:互聯網
上載者:User

 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;

l      刪除元素

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. 動態建立的含義

 

舉例說明:

還是有個直線類,現在要序列化儲存。

 

l          添加元素

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

m_array.Add(line); //CObArray m_array;  類中的成員變數

 

l           

在文檔類中儲存和讀取

 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;

}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.