MFC 的CList,CPtrList,CObList,CStringList 的用法之CList

CList 類

C++中實現通用數據結構

在程序設計當中經常會出現使用同種數據結構的不同實例的情況。例如:在一個
程序中可以使用多個隊列、樹、圖等結構來組織數據。同種結構的不同實例,也
許只在數據元素的類型或數量上略有差異,如果對每個實例都重新定義,則非常麻
煩且容易出錯。那麼能否對同種類型數據結構僅定義一次呢?答案是肯定的,C++
提供的類模板(Class Template)就可以實現該功能。
一、類模板
類模板是C++提供的一種特殊機制,通過它我們可以定義一種特殊的類(稱爲模板
類),在類的定義中可以包含待定的類型參數,在聲明類的實例時,系統會自動根據
傳遞的類型生成用戶想要生成的類實例。下面是用C++實現的一個簡單的模板類
Clist的定義。
Template <class T, int I> class CList
{
public:
int SetItem(int Index, const T &Item);
int GetItem(int Index, T &Item);
private:
T Buffer[I];
}
在這裏,T是類型參數,I是整型常量參數。T和I的實際值是在聲明具體類實例時指
定的。模板類的<>號內可以包括任意個類型參數和常量參數(至少要有一個參數
)。類型參數和常量參數可以是任何合法的標準類型和用戶自定義類型,包括簡單
類型及各種結構體。同其他類一樣,類成員函數SetItem的實現可以在類定義內完
成,也可以在類CList定義處實現:
template<class T, int I> int CList<T, I>::SetItem(int Index, const T
&Item)
{
if ( (Index<0)||(Index>I-1) )
 return 0; // 出錯
Buffer[Index]= Item ;
 return 1; // 成功
}
值得注意的是,在類定義外完成函數實現時,必須以關鍵字template和類模板定義
中相同的參數表(<>號內的)開頭(上例爲template<class T, int I>),並且範圍
分解操作符前的類名後應跟上模板參數名清單(上例爲CList<T, I>)。另外,與非
模板類不同的是,必須將函數實現包括在調用它的每個源文件中,使編譯器能從函
數實現產生代碼。通常的做法是將模板類的函數實現也放在定義該類的頭文件中
,這樣只需在調用的源文件中包含該頭文件即可。
那麼,如何使用生成特定的類實例呢?我們可以像使用其他類一樣來使用模板類,
不過必須指定模板參數的值。例如採用如下聲明:
CList <int, 100> IntList;
則使IntList成爲CList類的實例,每次出現的T參數都換成int, 每次出現的I參數
都換成100。這樣,IntList類中的Buffer就是一個長度爲100的整型數組,
SetItem和GetItem函數參數是int值的引用。例:
IntList.SetItem(0, 5); //給數組第一個元素賦爲整數5
模板類還可以像其他類一樣可以定義構造函數和析構函數。下面我們以一種簡單
的數據結構——堆棧爲例,來說明如何用類模板來構造通用數據結構。
二、 利用類模板實現通用堆棧結構
任何抽象數據結構在計算機中的實現,歸根結底都只有兩種方式:順序存儲(用數
組實現),鏈式存儲(用指針實現)。堆棧也不例外,按其實現方式可分爲順序棧(用
數組實現)和鏈棧(用指針實現)。
1. 通用順序棧的實現
因爲順序棧中的元素在空間上連續存儲,棧頂的元素位置需要註明,所以構造順序
棧的模板類應該有這樣的一些成員變量:一個待定類型和長度的數組Buffer,一個
記錄棧頂元素的數組下標的整型變量top。堆棧的基本操作主要有:入棧(Push)、
出棧(Pop)、置空(SetEmpty)、判斷當前狀態(IsEmpty)等,它們應用模板類的成
員函數來實現。作爲一個標準的類,它還應該有自己的構造函數和析構函數。具
有這些功能的模板類,就可以作爲一個通用的順序棧來使用了。該類的定義如下
:
template <class T,int SIZE> class CArrayStackTemp
{
public:
CArrayStackTemp () //缺省構造函數,構造一個空堆棧
{
top= -1;
};
~ CArrayStackTemp (){};//析構函數
 void SetEmpty (); //置空堆棧
 bool IsEmpty(); //判斷堆棧是否爲空
 bool Push(T element); //入棧
 bool Pop(T& element);//出棧
private:
T Buffer[SIZE];
 int top;
};
與堆棧的基本操作相對應的成員函數的實現如下:
template <class T, int SIZE> void CArrayStackTemp<T, SIZE>::
SetEmpty ()
{
top= -1; //將棧頂指針賦 -1,並不實際清除數組元素
}
template <class T, int SIZE> bool CArrayStackTemp<T, SIZE>:: IsEmpty
()
{
return(top == -1);
}
template <class T, int SIZE> bool CArrayStackTemp<T, SIZE>:: Push (T
element)
{
top++;
if (top>SIZE-1)
{
top--;
return false; //堆棧已滿,不能執行入棧操作
}
Buffer[top]=element;
return true;
}
template <class T, int SIZE> void CArrayStackTemp<T, SIZE>:: Pop (T&
element)
{
if (IsEmpty())
 return false;
element =Buffer[top];
top--;
return true;
}
根據實際需要,還可以擴充堆棧功能。例如:加入取棧頂元素、求堆棧長度等操作
,其方法如上。
2. 通用鏈棧的實現
模板類中允許使用指針和定義自己的結構,這就爲實現鏈式結構提供了保證。這
裏採用一個單鏈表來實現堆棧,棧頂指針指向鏈表的第一個結點,入棧和出棧均在
鏈表的頭進行。該模板類的定義如下:
template <class T> class CLinkStackTemp
{
public:
 //類的缺省構造函數,生成一個空堆棧
CLinkStackTemp ()
{
top=NULL;
};
~ClinkStackTemp(){}; //析構函數
 //定義結點結構
 struct node
{
T
  data; //入棧元素
 node* next; //指向下一結點的指針
};
 void SetEmpty(); //置空堆棧
 bool IsEmpty(); //判斷堆棧是否爲空
 bool Push(T element); //壓入堆棧
 bool Pop(T& element);//彈出堆棧
private:
 node* top;
};
該類的成員函數實現如下:
template <class T> void CLinkStackTemp <T>::SetEmpty()
{
//釋放堆棧佔用的內存
node* temp;
while (top!=NULL)
{
 temp=top;
 top=top->next;
 delete temp;
}
}
template <class T> bool CLinkStackTemp <T>::IsEmpty()
{
return (top==NULL);
}
template <class T> bool CLinkStackTemp <T>::Push(T element)
{
node* temp=new node();
if (temp ==NULL)
 return false ;
temp->data=element;
temp->next=top;
top=temp;
return true;
}
template <class T> bool CLinkStackTemp <T>::Pop(T& element)
{
if ( IsEmpty())
 return false;
node* q = top;
element = top->data;
top=top->next;
delete q;

return true;
}
與順序棧的實現略有不同,鏈棧不必指定棧的容量,其大小可以是近似"無限"的。
爲了程序的使用方便,我們同樣可以加入一些增強的功能。
三、 通用堆棧類的使用
通用堆棧類的使用較爲簡單,堆棧類的實例就是一個可以方便使用的堆棧。對堆
棧的操作都是通過類的成員函數來實現的。使用的具體步驟如下:
1. 在要使用堆棧類的程序代碼的文件開頭包括模板類及其成員函數的定義。
2. 類的實例化,可聲明成變量,也可以聲明它的指針,如:
CArrayStackTemp <int, 100> intStack; //生成一個長度爲100的int型堆棧
//生成一個元素爲Record型的堆棧,Record爲自定義結構
CLinkStackTemp <Record>* RecordStack;
RecordStack=new CLinkStackTemp<Record>;
應注意在定義順序棧時,必須指定棧的大小,而鏈棧則不必。另外在指定指針類型
和執行new操作時,必須對模板參數賦值,並且前後要一致。
3. 對堆棧進行操作,如:
intStack.Push(3); //將整數3入棧
RecordStack.SetEmpty(); //將堆棧置空
無論我們使用哪種堆棧類,對用戶來講都是透明的,操作起來並無差別。

CList類的兩個參數什麼意思啊?第一個參數表示鏈表中存儲的數據類型,後面一個表示鏈表類中函數參數的傳遞方式,通常爲存儲數據類型的引用。
CList<string,string> MyList_x;
CList<string,string&>MyList_y;
//兩種方式實現的功能一樣,不過後面一個更加高效。
CList <int,string> list;聲明方式就是錯誤,
CList <int,int>list1;CList <int,char>list2;CList<char,int> list3;都是可以接受的聲明方式。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章