从MFC中的CSinpleList学到的东西

源自:小银

stack是一种先进后出(First in last out)的数据结构,queue是一种先进先出(first in first out)的数据结构,在stl中实现方法是用了把deque双向队列封装了一下(具体可以查看<<stl源妈解析>>大概是第4章).
今天剥离MFC中CWinThread的类时,发现是一个MFC存放线程信息的一个队列类CSimpleList,是个队列的类和以前看到的方法都不一样它用了位移来得到p->next(比较牛啊).具体代码从MFC中剥离了出来,根据这种想法又写了stack和queue的两个类,其实是想写list的嫌麻烦,就改简单的了.重在思想.

先给出 CSimpleList代码

Simplelist.h
#ifndef __JONES__CSIMPLELIST__
#define __JONES__CSIMPLELIST__

class CSimpleList
{
public:
 CSimpleList(
int nNextOffset = 0);
 
void Construct(int nNextOffset);

//操作
 BOOL IsEmpty() const;
 
void AddHead(void* p);
 
void RemoveAll();
 
void* GetHead() const;
 
void* GetNext(void* p) const;
 BOOL Remove(
void* p);
 
void** GetNextPtr(void* p) const

private:
 
void* m_pHead;
 size_t m_nNextOffset;  
//pNext的位移偏量

}
;

//对CSimpleList的一个封装
template<class TYPE>
class CTypedSimpleList : public CSimpleList
{
public:
 CTypedSimpleList(
int nNextOffset = 0)
  : CSimpleList(nNextOffset) 
{ }
 
void AddHead(TYPE p)
  
{ CSimpleList::AddHead(p); }
 TYPE GetHead()
  
return (TYPE)CSimpleList::GetHead(); }
 TYPE GetNext(TYPE p)
  
return (TYPE)CSimpleList::GetNext(p); }
 BOOL Remove(TYPE p)
  
return CSimpleList::Remove((TYPE)p); }
 
operator TYPE()
  
return (TYPE)CSimpleList::GetHead(); }
}
;

#endif

#include 
"stdafx.h"
#include 
"SimpleList.h"

CSimpleList::CSimpleList(
int nNextOffset)

 m_pHead 
= NULL; 
 m_nNextOffset 
= nNextOffset; 
}


void CSimpleList::Construct(int nNextOffset) 

 assert(m_pHead 
== NULL); 
 m_nNextOffset 
= nNextOffset; 
}


BOOL CSimpleList::IsEmpty() 
const

 
return m_pHead == NULL; 
}



void** CSimpleList::GetNextPtr(void* p) const

 assert(p 
!= NULL); 
 
return (void**)((BYTE*)p+m_nNextOffset);   
//重点啊 配合下面的g_list.Construct(offsetof(CThreadData, pNext)); 一起看,然后画个图 是不是得到是pNext的位置
}



void CSimpleList::RemoveAll()

 m_pHead 
= NULL; 
}



void* CSimpleList::GetHead() const

 
return m_pHead; 
}


void* CSimpleList::GetNext(void* prevElement) const

 
return *GetNextPtr(prevElement); 
}


void CSimpleList::AddHead(void* p)
{
 assert(p 
!= NULL);
 assert(
*GetNextPtr(p) == NULL);

 
*GetNextPtr(p) = m_pHead;
 m_pHead 
= p;
}


BOOL CSimpleList::Remove(
void* p)
{
 assert(p 
!= NULL);

 
if (m_pHead == NULL)
  
return FALSE;

 BOOL bResult 
= FALSE;
 
if (m_pHead == p)
 
{
  m_pHead 
= *GetNextPtr(p);
  bResult 
= TRUE;
 }

 
else
 
{
  
void* pTest = m_pHead;
  
while (pTest != NULL && *GetNextPtr(pTest) != p)
   pTest 
= *GetNextPtr(pTest);
  
if (pTest != NULL)
  
{
   
*GetNextPtr(pTest) = *GetNextPtr(p);
   bResult 
= TRUE;
  }

 }

 
return bResult;
}


//调用了

struct CThreadData
{
 CThreadData
* pNext; 
 
int nCount;        
 LPVOID
* pData;      
}
;


CTypedSimpleList
<CThreadData*> g_list;
int main(int argc, char* argv[])
{
 g_list.Construct(offsetof(CThreadData, pNext)); 
//得到pNext的和CThreadData的偏量
 CThreadData* pData=NULL,
 pData 
= new CThreadData;
 pData
->nCount = 0;
 pData
->pData = NULL;
 pData
->pNext=NULL;
 g_list.AddHead(pData);

 pData 
= new CThreadData;
 pData
->nCount = 1;
 pData
->pData = NULL;
 pData
->pNext=NULL;
 g_list.AddHead(pData);

 pData 
= new CThreadData;
 pData
->nCount = 2;
 pData
->pData = NULL;
 pData
->pNext=NULL;
  
 g_list.AddHead(pData);

 pData
=g_list;
 
while(pData=g_list.GetNext(pData))
 
{
      printf(
"%d\r\n",pData->nCount);
 }

.delete掉new出来的东西(略) 可以调Remove() 然后delete
}

 //下面是我自己根据这个原理写的stock和queue 最后用模版封装了一下

#ifndef __JONES_QUEUE__STOCK
#define __JONES_QUEUE__STOCK

class ListBase //list基类
{
public:
 
void Construct(int nNextOffset); //pNext的位移

protected:
 
void** GetNextPtr(void* p) const//利用位移得到pNext地址
 size_t m_nNextOffset; //偏移量
}
;


/********************************************************************/
/******************QueueList 先进先出********************************/
/********************************************************************/
class QueueList : public ListBase
{
public:
 QueueList(
int nNextOffset=0);

//操作
 bool empty() const;
 
void* front() const//得到栈的第一个数据
 void pop(); //出栈
 void push(void* p); //压栈
private:
 
void* m_pHead; //
 void* m_pTail; //
}
;


/********************************************************************/
/******************StockList 先进后出********************************/
/********************************************************************/
class StockList : public ListBase
{
public:
 StockList(
int nNextOffset=0);
 
void pop(); //出栈
 void push(void* p); //压栈
 void* front() const//得到栈的第一个数据
private:
 
void* m_pHead; //
}
;

/********************************************************************/
/*封装了一下 好看点而已(起码也用到模版了,现在流行的技术,呵呵..) */
/********************************************************************/
template 
<typename TYPE,typename LISTTYPE=QueueList /*list类型*/>
class SpecialList : public LISTTYPE
{
public:
 SpecialList(
int nNextOffset=0)
  : LISTTYPE(nNextOffset)  
{}

 TYPE front()
  
return (TYPE)LISTTYPE::front(); }

 
void push(TYPE p)
  
{ LISTTYPE::push(p); }

}
;
#endif

//调用的例子
struct CThreadData
{
 CThreadData
* pNext; 
 
int nCount;     
 LPVOID
* pData; 
}
;

SpecialList
<CThreadData*,QueueList> g_Queue;

int main(int argc, char* argv[])

 g_Queue.Construct(offsetof(CThreadData, pNext));
 CThreadData
* pData=NULL,*pTemp=NULL;
 pData 
= new CThreadData;
 pData
->nCount = 0;
 pData
->pData = NULL;
 pData
->pNext=NULL;
 g_Queue.push(pData);

 pData 
= new CThreadData;
 pData
->nCount = 1;
 pData
->pData = NULL;
 pData
->pNext=NULL;
 g_Queue.push(pData);

 pData 
= new CThreadData;
 pData
->nCount = 2;
 pData
->pData = NULL;
 pData
->pNext=NULL; 
 g_Queue.push(pData);

 
while(pData=g_Queue.front())
 
{
  printf(
"%d\r\n",pData->nCount);
  g_Queue.pop();
  delete pData;
 }

 
  
return 0;
}


最后忘了说还有1点就是 如果你用的是继承的数据
class CNoTrackObject
{
public:
 
virtual ~CNoTrackObject() {};

}
;

struct CThreadData : public CNoTrackObject
{
 CThreadData
* pNext; 
 
int nCount;         
 LPVOID
* pData;     )
}
;


那pNext位移的偏量就不是0了是4,具体可以查看<<c++对象模型>>

原文地址:https://www.cnblogs.com/powersun/p/972028.html