from:
1 http://hi.baidu.com/jiaxi2000/blog/item/d3d02b3f3b1f6aee54e72381.html
CList的用法
2007-06-21 09:26
这是一个集合类,也是一个双向链表类,是一个类模板
他的定义如下:
template< class
TYPE
, class
ARG_TYPE
>class CList : public CObject
使用
第一个参数是实例化的类型,第二个参数是类的成员函数的参数的调用形式,通常是类型 引用
一个矩形类Rectangle的类模板:
template
<
class
T
>
class
Rectangle
{
private: T width, height; public: Rectangle(T w, T h); //构造函数 T area(); } ;
在类中,形参T被引用在数据成员width和height的类型及成员函数area返回值的类型上,它是根据将来
程序中声明时指定的类型而定,如在主程序中声明:
Rectangle<int> r1(20,3);
则类模板中的形参T会以int替代,产生以整数为主的Rectangle对象r1 ;
另外,成员函数如果
设计在类外,除了要标明其所属的类名称外,还需要加上模板的声明,且类名称也要加上用
尖括号括起来的形参行。如上例中的成员函数Rectangle(T w, T h)和area(),其写法如下:
template
<
class
T
>
Rectangle
<
T
>
::Rectangle(T w,T h)
... { width = w; height = h; } template < class T > T Rectangle < T > ::area() ... { return width*height; }
--------------
具有固定类型的类模板
类模板的形参行,不仅可以使用未定类型的类,也可指定固定的类型,如下:
template
<
class
T,
int
n
>
class
Array
...
{
private: T data[n]; public: Array()...{} //构造函数 void add_data(int i, T d); //将数据填入数组中 Array<T,n > operator+(Array<T,n> a); //数组相加 void display(); } ;
如使用这类模板时,如下:
Array<double, 3> dbl1;
表示声明了一个Array对象,其中的数据是double类型,且其数组大小为3,其作用相当于声明了
double data[3].
=================
Afxtempl.h 中的CList
//
CList<TYPE, ARG_TYPE>
template < class TYPE, class ARG_TYPE > class CList : public CObject ... { protected: struct CNode ...{ CNode* pNext; CNode* pPrev; TYPE data; }; public: // Construction CList(int nBlockSize = 10); // Attributes (head and tail) // count of elements int GetCount() const; BOOL IsEmpty() const; // peek at head or tail TYPE& GetHead(); TYPE GetHead() const; TYPE& GetTail(); TYPE GetTail() const; // Operations // get head or tail (and remove it) - don't call on empty list ! TYPE RemoveHead(); TYPE RemoveTail(); // add before head or after tail POSITION AddHead(ARG_TYPE newElement); POSITION AddTail(ARG_TYPE newElement); // add another list of elements before head or after tail void AddHead(CList* pNewList); void AddTail(CList* pNewList); // remove all elements void RemoveAll(); // iteration POSITION GetHeadPosition() const; POSITION GetTailPosition() const; TYPE& GetNext(POSITION& rPosition); // return *Position++ TYPE GetNext(POSITION& rPosition) const; // return *Position++ TYPE& GetPrev(POSITION& rPosition); // return *Position-- TYPE GetPrev(POSITION& rPosition) const; // return *Position-- // getting/modifying an element at a given position TYPE& GetAt(POSITION position); TYPE GetAt(POSITION position) const; void SetAt(POSITION pos, ARG_TYPE newElement); void RemoveAt(POSITION position); // inserting before or after a given position POSITION InsertBefore(POSITION position, ARG_TYPE newElement); POSITION InsertAfter(POSITION position, ARG_TYPE newElement); // helper functions (note: O(n) speed) POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL) const; // defaults to starting at the HEAD, return NULL if not found POSITION FindIndex(int nIndex) const; // get the 'nIndex'th element (may return NULL) // Implementation protected: CNode* m_pNodeHead; CNode* m_pNodeTail; int m_nCount; CNode* m_pNodeFree; struct CPlex* m_pBlocks; int m_nBlockSize; CNode* NewNode(CNode*, CNode*); void FreeNode(CNode*); public: ~CList(); void Serialize(CArchive&); #ifdef _DEBUG void Dump(CDumpContext&) const; void AssertValid() const; #endif } ; /**/ ///// // CList<TYPE, ARG_TYPE> inline functions template < class TYPE, class ARG_TYPE > AFX_INLINE int CList < TYPE, ARG_TYPE > ::GetCount() const ... { return m_nCount; } template < class TYPE, class ARG_TYPE > AFX_INLINE BOOL CList < TYPE, ARG_TYPE > ::IsEmpty() const ... { return m_nCount == 0; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE & CList < TYPE, ARG_TYPE > ::GetHead() ... { ASSERT(m_pNodeHead != NULL); return m_pNodeHead->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE CList < TYPE, ARG_TYPE > ::GetHead() const ... { ASSERT(m_pNodeHead != NULL); return m_pNodeHead->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE & CList < TYPE, ARG_TYPE > ::GetTail() ... { ASSERT(m_pNodeTail != NULL); return m_pNodeTail->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE CList < TYPE, ARG_TYPE > ::GetTail() const ... { ASSERT(m_pNodeTail != NULL); return m_pNodeTail->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE POSITION CList < TYPE, ARG_TYPE > ::GetHeadPosition() const ... { return (POSITION) m_pNodeHead; } template < class TYPE, class ARG_TYPE > AFX_INLINE POSITION CList < TYPE, ARG_TYPE > ::GetTailPosition() const ... { return (POSITION) m_pNodeTail; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE & CList < TYPE, ARG_TYPE > ::GetNext(POSITION & rPosition) // return *Position++ ... { CNode* pNode = (CNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); rPosition = (POSITION) pNode->pNext; return pNode->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE CList < TYPE, ARG_TYPE > ::GetNext(POSITION & rPosition) const // return *Position++ ... { CNode* pNode = (CNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); rPosition = (POSITION) pNode->pNext; return pNode->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE & CList < TYPE, ARG_TYPE > ::GetPrev(POSITION & rPosition) // return *Position-- ... { CNode* pNode = (CNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); rPosition = (POSITION) pNode->pPrev; return pNode->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE CList < TYPE, ARG_TYPE > ::GetPrev(POSITION & rPosition) const // return *Position-- ... { CNode* pNode = (CNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); rPosition = (POSITION) pNode->pPrev; return pNode->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE & CList < TYPE, ARG_TYPE > ::GetAt(POSITION position) ... { CNode* pNode = (CNode*) position; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); return pNode->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE TYPE CList < TYPE, ARG_TYPE > ::GetAt(POSITION position) const ... { CNode* pNode = (CNode*) position; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); return pNode->data; } template < class TYPE, class ARG_TYPE > AFX_INLINE void CList < TYPE, ARG_TYPE > ::SetAt(POSITION pos, ARG_TYPE newElement) ... { CNode* pNode = (CNode*) pos; ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); pNode->data = newElement; } template < class TYPE, class ARG_TYPE > CList < TYPE, ARG_TYPE > ::CList( int nBlockSize) ... { ASSERT(nBlockSize > 0); m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; m_nBlockSize = nBlockSize; } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::RemoveAll() ... { ASSERT_VALID(this); // destroy elements CNode* pNode; for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext) DestructElements<TYPE>(&pNode->data, 1); m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks->FreeDataChain(); m_pBlocks = NULL; } template < class TYPE, class ARG_TYPE > CList < TYPE, ARG_TYPE > :: ~ CList() ... { RemoveAll(); ASSERT(m_nCount == 0); } /**/ ///// // Node helpers // // Implementation note: CNode's are stored in CPlex blocks and // chained together. Free blocks are maintained in a singly linked list // using the 'pNext' member of CNode with 'm_pNodeFree' as the head. // Used blocks are maintained in a doubly linked list using both 'pNext' // and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail' // as the head/tail. // // We never free a CPlex block unless the List is destroyed or RemoveAll() // is used - so the total number of CPlex blocks may grow large depending // on the maximum past size of the list. // template < class TYPE, class ARG_TYPE > CList < TYPE, ARG_TYPE > ::CNode * CList < TYPE, ARG_TYPE > ::NewNode(CList::CNode * pPrev, CList::CNode * pNext) ... { if (m_pNodeFree == NULL) ...{ // add another block CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CNode)); // chain them into free list CNode* pNode = (CNode*) pNewBlock->data(); // free in reverse order to make it easier to debug pNode += m_nBlockSize - 1; for (int i = m_nBlockSize-1; i >= 0; i--, pNode--) ...{ pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; } } ASSERT(m_pNodeFree != NULL); // we must have something CList::CNode* pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; pNode->pPrev = pPrev; pNode->pNext = pNext; m_nCount++; ASSERT(m_nCount > 0); // make sure we don't overflow ConstructElements<TYPE>(&pNode->data, 1); return pNode; } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::FreeNode(CList::CNode * pNode) ... { DestructElements<TYPE>(&pNode->data, 1); pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; m_nCount--; ASSERT(m_nCount >= 0); // make sure we don't underflow // if no more elements, cleanup completely if (m_nCount == 0) RemoveAll(); } template < class TYPE, class ARG_TYPE > POSITION CList < TYPE, ARG_TYPE > ::AddHead(ARG_TYPE newElement) ... { ASSERT_VALID(this); CNode* pNewNode = NewNode(NULL, m_pNodeHead); pNewNode->data = newElement; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = pNewNode; else m_pNodeTail = pNewNode; m_pNodeHead = pNewNode; return (POSITION) pNewNode; } template < class TYPE, class ARG_TYPE > POSITION CList < TYPE, ARG_TYPE > ::AddTail(ARG_TYPE newElement) ... { ASSERT_VALID(this); CNode* pNewNode = NewNode(m_pNodeTail, NULL); pNewNode->data = newElement; if (m_pNodeTail != NULL) m_pNodeTail->pNext = pNewNode; else m_pNodeHead = pNewNode; m_pNodeTail = pNewNode; return (POSITION) pNewNode; } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::AddHead(CList * pNewList) ... { ASSERT_VALID(this); ASSERT(pNewList != NULL); ASSERT_VALID(pNewList); // add a list of same elements to head (maintain order) POSITION pos = pNewList->GetTailPosition(); while (pos != NULL) AddHead(pNewList->GetPrev(pos)); } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::AddTail(CList * pNewList) ... { ASSERT_VALID(this); ASSERT(pNewList != NULL); ASSERT_VALID(pNewList); // add a list of same elements POSITION pos = pNewList->GetHeadPosition(); while (pos != NULL) AddTail(pNewList->GetNext(pos)); } template < class TYPE, class ARG_TYPE > TYPE CList < TYPE, ARG_TYPE > ::RemoveHead() ... { ASSERT_VALID(this); ASSERT(m_pNodeHead != NULL); // don't call on empty list !!! ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode))); CNode* pOldNode = m_pNodeHead; TYPE returnValue = pOldNode->data; m_pNodeHead = pOldNode->pNext; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = NULL; else m_pNodeTail = NULL; FreeNode(pOldNode); return returnValue; } template < class TYPE, class ARG_TYPE > TYPE CList < TYPE, ARG_TYPE > ::RemoveTail() ... { ASSERT_VALID(this); ASSERT(m_pNodeTail != NULL); // don't call on empty list !!! ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode))); CNode* pOldNode = m_pNodeTail; TYPE returnValue = pOldNode->data; m_pNodeTail = pOldNode->pPrev; if (m_pNodeTail != NULL) m_pNodeTail->pNext = NULL; else m_pNodeHead = NULL; FreeNode(pOldNode); return returnValue; } template < class TYPE, class ARG_TYPE > POSITION CList < TYPE, ARG_TYPE > ::InsertBefore(POSITION position, ARG_TYPE newElement) ... { ASSERT_VALID(this); if (position == NULL) return AddHead(newElement); // insert before nothing -> head of the list // Insert it before position CNode* pOldNode = (CNode*) position; CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode); pNewNode->data = newElement; if (pOldNode->pPrev != NULL) ...{ ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode))); pOldNode->pPrev->pNext = pNewNode; } else ...{ ASSERT(pOldNode == m_pNodeHead); m_pNodeHead = pNewNode; } pOldNode->pPrev = pNewNode; return (POSITION) pNewNode; } template < class TYPE, class ARG_TYPE > POSITION CList < TYPE, ARG_TYPE > ::InsertAfter(POSITION position, ARG_TYPE newElement) ... { ASSERT_VALID(this); if (position == NULL) return AddTail(newElement); // insert after nothing -> tail of the list // Insert it before position CNode* pOldNode = (CNode*) position; ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode))); CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext); pNewNode->data = newElement; if (pOldNode->pNext != NULL) ...{ ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode))); pOldNode->pNext->pPrev = pNewNode; } else ...{ ASSERT(pOldNode == m_pNodeTail); m_pNodeTail = pNewNode; } pOldNode->pNext = pNewNode; return (POSITION) pNewNode; } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::RemoveAt(POSITION position) ... { ASSERT_VALID(this); CNode* pOldNode = (CNode*) position; ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode))); // remove pOldNode from list if (pOldNode == m_pNodeHead) ...{ m_pNodeHead = pOldNode->pNext; } else ...{ ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode))); pOldNode->pPrev->pNext = pOldNode->pNext; } if (pOldNode == m_pNodeTail) ...{ m_pNodeTail = pOldNode->pPrev; } else ...{ ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode))); pOldNode->pNext->pPrev = pOldNode->pPrev; } FreeNode(pOldNode); } template < class TYPE, class ARG_TYPE > POSITION CList < TYPE, ARG_TYPE > ::FindIndex( int nIndex) const ... { ASSERT_VALID(this); if (nIndex >= m_nCount || nIndex < 0) return NULL; // went too far CNode* pNode = m_pNodeHead; while (nIndex--) ...{ ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); pNode = pNode->pNext; } return (POSITION) pNode; } template < class TYPE, class ARG_TYPE > POSITION CList < TYPE, ARG_TYPE > ::Find(ARG_TYPE searchValue, POSITION startAfter) const ... { ASSERT_VALID(this); CNode* pNode = (CNode*) startAfter; if (pNode == NULL) ...{ pNode = m_pNodeHead; // start at head } else ...{ ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); pNode = pNode->pNext; // start after the one specified } for (; pNode != NULL; pNode = pNode->pNext) if (CompareElements<TYPE>(&pNode->data, &searchValue)) return (POSITION)pNode; return NULL; } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::Serialize(CArchive & ar) ... { ASSERT_VALID(this); CObject::Serialize(ar); if (ar.IsStoring()) ...{ ar.WriteCount(m_nCount); for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext) ...{ ASSERT(AfxIsValidAddress(pNode, sizeof(CNode))); SerializeElements<TYPE>(ar, &pNode->data, 1); } } else ...{ DWORD nNewCount = ar.ReadCount(); while (nNewCount--) ...{ TYPE newData; SerializeElements<TYPE>(ar, &newData, 1); AddTail(newData); } } } #ifdef _DEBUG template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::Dump(CDumpContext & dc) const ... { CObject::Dump(dc); dc << "with " << m_nCount << " elements"; if (dc.GetDepth() > 0) ...{ POSITION pos = GetHeadPosition(); while (pos != NULL) ...{ dc << " "; DumpElements<TYPE>(dc, &((CList*)this)->GetNext(pos), 1); } } dc << " "; } template < class TYPE, class ARG_TYPE > void CList < TYPE, ARG_TYPE > ::AssertValid() const ... { CObject::AssertValid(); if (m_nCount == 0) ...{ // empty list ASSERT(m_pNodeHead == NULL); ASSERT(m_pNodeTail == NULL); } else ...{ // non-empty list ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode))); ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode))); } } #endif // _DEBUG
=========================
因此如下:
typedef CList<CString ,CString &> strlist;
strlist str;
or
CList<CString ,CString &> str;
这样就定义了一个CString类型的双向链表str;
这样可以看出
ARG_TYPE主要指定
CList的方法对于TYPE的引用方法。
例如: 1) CList<string, string> list; POSITION AddHead(string newElement); 这是AddHead参数为 传值 2) CList<string, string&> list; POSITION AddHead(string& newElement); 这是AddHead参数为传 引用 |