• 从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++对象模型>>

  • 相关阅读:
    教你如何上传项目到GitHub
    Spring Boot日志使用
    Github库名命名规范
    failed to resolve org.junit.platform
    SecureCRT 关键字高亮显示
    curl 命令
    idea中展开折叠的文件夹
    python官网打不开
    小工具下载地址汇总
    Navicat12 for Mysql激活
  • 原文地址:https://www.cnblogs.com/powersun/p/972028.html
Copyright © 2020-2023  润新知