Windows 程序设计学习记录(1)类的定义和应用

      最近开始学习Windows 程序设计,一边看那本王艳平写的书,一边练习编程,打算记录一下自己的学习过程和心得体会!!!!!!!!!

      今天学习了数据链表的建立,通过定义一个CSimpleList类来存储多个数据,通过建立的数据链表来实现对各个数据的添加,删除以及遍历表中的元素.遇到很多问题,很多难懂的地方,但不怕,慢慢来,一个一个解决.

       1、这个CSimpleList类是定义在一个_AFXTLS_.H头文件中,为了避免重复使用一组预编译指令:

View Code
#ifndef __AFXTLS_H__  //_AFXTLS_.H 文件
#define __AFXTLS_H__  

/*********************/

#endif

     下面是头文件_AFXTLS_.H中的内容。首先什么是类的内联函数??inline是啥啊?而且还写在类定义的外面,百度了一下,原来inline是代替C中表达式形式的宏定义,不但继

承了它没有参数压栈,没有代码生成等普通函数使用时需要的操作,而且还享受到C++编译器严格类型检查的好处,从而节省了很多时间,效率很高。具体的知识可以自己去找下。

     类定义中有个内联函数是

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

 { return (void**)((BYTE*)p + m_nNextOffset);}

      void**表示GetNextPtr这个成员函数是指向指针的指针类型的,后面的const是常函数的意思,表示这个成员函数不会改变类中的成员变量,只可读类中的成员,不可写。

      这个函数返回的是指针所在的地址,这个指针是什么呢?? 其实这个是一个结构体指针加上这个结构体里的一个成员的偏移量(有点难懂,想象一下这个结构体相当于一个数

组,这个结构体指针是数组的首地址,那么结构体里的多个成员存储在内存中,每个成员就相对于这个首地址有了一个偏移量)说白了,这个就是结构体里的那个成员的地址。    

View Code
#ifndef __AFXTLS_H__  //_AFXTLS_.H 文件
#define __AFXTLS_H__  

#include <Windows.h>
#include <stddef.h>


class CNoTrackObject;

//////////////////////////////////
///// CSimpleList  ///////////////

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

//提供给用户的接口函数 (Operations) , 用于添加\删除和遍历节点
    BOOL IsEmpty() const;
    void AddHead(void* p);
    void RemoveAll();
    void* GetHead() const;  //如果函数的参数可以是任意类型指针,那么应声明其参数为void * 
    void* GetNext(void* p) const;
    BOOL Remove(void* p);

//为实现接口函数所需要的成员 ( Implementation)
    void* m_pHead;          //链接中第一个元素的地址
    size_t m_nNextOffset;   
    //数据结构中pNext成员的偏移量,size_t 是无符号整数类型,
    //m_nNextOffset代表的是对象首地址到对象成员地址之间的偏移量
    void** GetNextPtr( void* p) const;   // 指向指针的指针
};

//类的内联函数????????????????????????????
inline CSimpleList::CSimpleList( int nNextOffset)
      { m_pHead = NULL;m_nNextOffset = nNextOffset;}
inline void CSimpleList::Construct(int nNextOffset)
      { m_nNextOffset = nNextOffset;}
inline BOOL CSimpleList::IsEmpty() const
      { return m_pHead == NULL;}
inline void CSimpleList::RemoveAll()
      { m_pHead = NULL;}
inline void* CSimpleList::GetHead() const
      { return m_pHead;}
inline void* CSimpleList::GetNext( void* preElement) const
      { return *GetNextPtr(preElement);}
inline void** CSimpleList::GetNextPtr(void* p) const
      { return (void**)((BYTE*)p + m_nNextOffset);}

      好的,再来看看在AFXTLS.CPP里面的内容,很奇怪,为什么CSimpleList::AddHead(void* p)CSimpleList::Remove(void* p)这两个个接口函数定义在

AFXTLS.CPP中呢?为什么不直接在头文件中定义好呢?当然又是百度一下,http://bbs.chinaunix.net/archiver/?tid-1610751.html,这个是讲解得最清楚的,非常好,都是牛人啊!

       为了加深我的理解,我还是概括一下吧,头文件一般是进行声明用的,而.cpp文件一般是代码的实现,为什么要这样规定呢?因为如果头文件想包含谁就包含谁,一来头文件

很大,预编译慢,二来这头文件不敢改了,如果改了,包含了这个头文件的文件也会改,弄得很乱。

       CSimpleList::AddHead(void* p)这个函数用于向链表中添加一个元素,并把新添加的元素放在表头,我们通过CSimpleList类中的m_pHead成员来标识第一个元素的地址

        *GetNextPtr(p) = m_pHead;        

     m_pHead = p;

相当于: void*t;

     t=GetNextPtr(p) ;      //t是指向结构体P中那个成员的地址的指针     

     *t= m_pHead;          //指针 t 指向链表中第一个元素的地址

     m_pHead = p;          //链表中一个元素的地址为传入的结构体指针

    还有个疑问,在CSimpleList::Remove(void* p)中,为什么移除头元素是下面的代码:

                    m_pHead = *GetNextPtr(p);      //把结构体中pNext成员的地址作为链表中第一个元素的地址,这里要明白链表的意思。可以这样理解,链表中的

元素既存有自己的数据,又存有下一个元素的地址,pNext成员就是存下一个元素的地址的,现在明白为什么把结构体中的pNext成员的地址作为链表中的第一个元素的地址就

是移除头元素了。

View Code
#include "_AFXTLS_.h"


//--------------------------------------

void CSimpleList::AddHead(void* p)
{
    *GetNextPtr(p) = m_pHead;
    m_pHead = p;
}

BOOL CSimpleList::Remove(void* p)
{
    if(p == NULL)    
        return FALSE;

    BOOL bResult = FALSE;     //假设移除失败
    if(p == m_pHead)
    {
        //要移除头元素
        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;
}

下面是这个类的一个实例代码,在MyTls.cpp文件中

View Code
#include "_AFXTLS_.h"
#include <process.h>
#include <iostream>
using namespace std;


struct MyThreadData
{
    MyThreadData* pNext;
    int nSomeData;
};


void main()
{
    MyThreadData* pData;
    //CTypedSimpleList<MyThreadData*> list;
    CSimpleList list;
    list.Construct(offsetof(MyThreadData, pNext));   //告诉CSimpleList类pNext成员的偏移量

    //向链表中添加成员
    for( int i = 0;i<10;i++)
    {
        pData = new MyThreadData;
        pData->nSomeData = i;
        list.AddHead(pData);
    }

    //......   ........   //使用链表中的数据

    //遍历整个链表,释放MyThreadData对象占用的空间
    pData = (MyThreadData*)list.GetHead();
    while(pData != NULL)
    {
        MyThreadData* pNextData = pData->pNext;
        printf( "The value of nSomeData is: %d \n",pData->nSomeData);
        delete pData;
        pData = pNextData;
    }
}
原文地址:https://www.cnblogs.com/YungMing/p/Ming.html