zz CList的用法

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参数为传 引用  
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值