可回收重复使用的链表,类似于Android消息链(并记录多态使用)

在尾部生产,头部消耗的链表,数据增加可重复使用的功能。

新数据类型继承Nod,实现newNod方法即可。使用时没有模板那么方便,需要强转。

感觉newNod和Windows好多结构体有个表示结构体大小的成员主要告诉new多大,使用时强转和CPtrList差不多。感觉这样设计也没啥不妥。

 回顾C++

 

// Demo.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"


#include<stdio.h>
#include <tchar.h>
#include<windows.h>

//为了 CRT 函数能够正常工作,#include 语句必须遵循此处所示的顺序。
//包含 crtdbg.h,将 malloc 和 free 函数映射到它们的调试版本,即 _malloc_dbg 和 free,它们将跟踪内存分配和释放。 
//此映射只在包含 _DEBUG 的调试版本中发生。 发布版本使用普通的 malloc 和 free 函数。
//#define 语句将 CRT 堆函数的基础版本映射到对应的调试版本。 如果省略 #define 语句,内存泄漏转储将有所简化。
//使用这些语句启用调试堆函数之后,可以在某个应用程序退出点之前设置一个对 _CrtDumpMemoryLeaks 的调用,以便在应用程序退出时显示内存泄漏报告:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

//不过,如果程序使用 C++ new 运算符分配内存,则需要重新定义 new 才能在内存泄漏报告中看到文件和行号。 您可以利用如下所示的代码块实现:
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif  // _DEBUG

#define CFREE(pPointer) if(pPointer){\
    ::free(pPointer);     pPointer = NULL; }

//_MSC_VER是MSVC编译器的内置宏,定义了编译器的版本。下面是一些编译器版本的_MSC_VER值
//MS VC++ 10.0 _MSC_VER = 1600
//MS VC++ 9.0 _MSC_VER = 1500
//MS VC++ 8.0 _MSC_VER = 1400
//MS VC++ 7.1 _MSC_VER = 1310
//MS VC++ 7.0 _MSC_VER = 1300
//MS VC++ 6.0 _MSC_VER = 1200
//MS VC++ 5.0 _MSC_VER = 1100

#if _MSC_VER <= 1200
#ifndef __STDC_WANT_SECURE_LIB__
#define sprintf_s sprintf
#define _stricmp stricmp
#endif
#endif


template<class Type>
struct TypedNod
{
    Type info;
    TypedNod<Type>* next;
};


class Nod
{
public:
    Nod *next;
    //C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为虚函数重写。
    //重写的话可以有两种,直接重写成员函数和重写虚函数,只有重写了虚函数的才能算作是体现了C++多态性
    virtual Nod* newNod(){
#ifdef _DEBUG
        printf("-Nod::newNod();\n");
#endif
        return new Nod();
    }

    static Nod* newNod0(){
#ifdef _DEBUG
        printf("-Nod::newNod0();\n");
#endif
        return new Nod();
    }

    virtual void release(){
#ifdef _DEBUG
        printf("-Nod::release();\n");
#endif
    }

    Nod(){
#ifdef _DEBUG
        printf("-Nod::Nod();\n");
#endif
        next = NULL;
    }
    virtual  ~Nod(){
#ifdef _DEBUG
        printf("-Nod::~Nod();\n");
#endif
    }

};

typedef Nod* NEWNODE(void);

class FileNod : public Nod
{
public:
    int mode;
    long size;
    char *path;
    void setPath(const char *p){
        path = strdup(p);
    }
    FileNod() :
        path(NULL){
#ifdef _DEBUG
        printf("--FileNod::FileNod();\n");
#endif
    }
    virtual ~FileNod(){
#ifdef _DEBUG
        printf("--FileNod::~FileNod();\n");
#endif
        release();
    }
    virtual Nod* newNod(){
#ifdef _DEBUG
        printf("--FileNod::newNod();\n");
#endif
        return new FileNod();
    }

    static Nod* newNod0(){
#ifdef _DEBUG
        printf("--FileNod::newNod0();\n");
#endif
        return new FileNod();
    }

    virtual void release(){
#ifdef _DEBUG
        printf("--FileNod::release();\n");
#endif
        CFREE(path);
    }
};


/*
* 我们没有清空回收到recyledPool项的数据域各字段,所以不推荐使用旧值,小心访问里面的数据。类似于硬盘删除文件,实际上没有把数据域重写(也是硬盘恢复工具)。提高性能。
*/
class RecyledQueue
{
public:
    Nod* header;
    Nod* tailer;
    int size;
    //废弃消息池(链)(就是废品收购站)
    Nod* recyledPool;
protected:

    //消息池当前大小
    int recyledPoolSize;
    // 消息池上限值
    //static const int MAX_POOL_SIZE  = 50; //vc下不支持这样
    const static int MAX_POOL_SIZE; // here initialize 
    Nod* hFactory;                //C++多态的应用
    NEWNODE *pfnNewNodFactory;    //函数指针不必每次new实例
public:
    RecyledQueue(NEWNODE pfnNewNod) :
        recyledPool(NULL), recyledPoolSize(0), header(NULL), tailer(NULL), size(0)

    {
        pfnNewNodFactory = pfnNewNod;
    }
    RecyledQueue(Nod* hNod) :
        recyledPool(NULL), recyledPoolSize(0), header(NULL), tailer(NULL), size(0)

    {
        hFactory = hNod;
    }
    ~RecyledQueue() {

        release(header, recyledPoolSize);
        release(recyledPool, size);
        //hFactory->release();
        delete hFactory;
        hFactory = NULL;
        header = NULL;
        tailer = NULL;

        printf("RecyledQueue::~RecyledQueue();\n");
    }
    //删除链表结点其实很简单,一般用到三个结构体指针变量和一个循环结构。
    void release(Nod* pNod, int& size) {
        Nod* pNext;
        while (pNod)
        {
            pNext = pNod->next; //q指向当前结点的下一个结点。
            delete pNod; //::free(p); //释放当前结点
            pNod = pNext; //p指向下一个结点
            size--;
        }
    }
    /**
    * Return a new Message instance from the global pool. Allows us to avoid allocating new objects
    * in many cases. 该函数内部首先是从全局的废弃消息池(链)中去取,看看有没有废弃掉的Message,如果有,那我们就获取消息链中第一个废弃掉的Message。
    * 这样,就无需再创建一个新的Message;如果消息池中没有,那就只能new一个新的消息出来。这样做的好处就是废物再利用,减少创建时间。
    * 实际上,这种思想很值得我们借鉴。对于其它重载版的obtain方法,内部都是先调用它,然后再使用其它额外的参数进行填充的。
    */
    Nod* obtain() {
        if (recyledPool != NULL)
        {
            Nod* m = recyledPool;
            recyledPool = m->next;
            m->next = NULL;
            recyledPoolSize--;
            return m;
        }
        if (hFactory){
#ifdef _DEBUG
            printf("\n\n----hFactory->newNod();\n");
#endif
            return hFactory->newNod(); //C++多态的应用
        }
        else if (pfnNewNodFactory){
#ifdef _DEBUG
            printf("\n\n----pfnNewNodFactory();\n");
#endif
            return pfnNewNodFactory();
        }
        return NULL;
    }

    /**
    * Return a Message instance to the global pool. You MUST NOT touch the Message after calling
    * this function -- it has effectively been freed.
    *
    * @return
    */
    RecyledQueue* recycle(Nod* node) {
        if (recyledPoolSize < MAX_POOL_SIZE)
        {
            //添加到消息链的头部
            node->next = recyledPool;
            //更新sPool指向当前
            recyledPool = node;
            recyledPoolSize++;
        }
        return this;
    }
    /**
    * Unlinks non-null first node.
    */
    RecyledQueue* unlinkFirst() {
        Nod* pTmpHeader = header;
        if (NULL != pTmpHeader)
        {
            header = pTmpHeader->next;
            pTmpHeader->next = NULL;
            //after unlinking the first, it is empty.
            if (header == NULL)
            {
                tailer = NULL;
            }
            size--;
            recycle(pTmpHeader);
        }
        return this;
    }

    /**
    * Links newNode as last element.
    */
    RecyledQueue* linkLast(Nod* newNode) {
        if (newNode != NULL)
        {
            //This linkedList is a empty queue.
            if (tailer == NULL)
            {
                header = newNode;
            }
            else
            {
                tailer->next = newNode;
            }
            tailer = newNode;
            size++;
        }
        return this;
    }
};

const int RecyledQueue::MAX_POOL_SIZE = 50;

void PrintLastError(int errorno)
{
#if defined(DEBUG) || defined(_DEBUG)
    LPVOID    lpMsgBuf;

    if (0 == errorno)
    {
        errorno = GetLastError();
    }
    /* dwFlags标志位,决定如何说明lpSource参数,dwFlags的低位制定如何处理换行功能在输出缓冲区,
    也决定最大宽度的格式化输出行。
    可选参数:

    标志                                标志说明

    FORMAT_MESSAGE_ALLOCATE_BUFFER        函数会分配一个足够大的缓冲区保存格式化消息,并且通过lpBuffer指向该地址。

    FORMAT_MESSAGE_ARGUMENT_ARRAY        Arguments参数不是指向va_list结构体,但是是一个指向保存参数的数据。

    FORMAT_MESSAGE_FROM_HMODULE            lpSource参数是需要去搜索的一个包含消息表的模块线程。如果lpSource是NULL,当前进程的
    应用图像会被搜索,这个标志不能同FORMAT_MESSAGE_FROM_STRING使用。

    FORMAT_MESSAGE_FROM_STRING            lpSource参数是一个指向以NULL结尾的字符串,字符串包含一个消息定义,这个消息定义可
    以包含插入序列。此标志最好不要和FORMAT_MESSAGE_FROM_HMODULE或者
    FORMAT_MESSAGE_FROM_SYSTEM使用

    FORMAT_MESSAGE_FROM_SYSTEM            0x00001000    函数会为了请求的信息而搜索系统的消息表资源。如果标志同时也指定了
    FORMAT_MESSAGE_FROM_HMODULE,那么函数会先在lpSource指定的模块中搜索请求的消息,
    如果搜索不到,就去搜索系统消息表资源。此标志不能与FORMAT_MESSAGE_FROM_STRING使用。

    FORMAT_MESSAGE_IGNORE_INSERTS        消息定义中的插入序列会被一直忽略和跳过直到输出缓冲区不改变,并且Arguments会被忽略。
    */
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, 0, (LPTSTR)&lpMsgBuf, 0, NULL);
#ifdef _CONSOLE
    printf("(%d), %s\r\n", errorno, lpMsgBuf);
#else
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, "错误", MB_OK | MB_TOPMOST);
#endif
    LocalFree(lpMsgBuf);

#endif
}

void show_file(char path[], RecyledQueue* pQueue, int level = 0)
{
    char findBuffer[256];
    sprintf_s(findBuffer, "%s*", path);
    WIN32_FIND_DATAA findFileData;
    HANDLE hFind = FindFirstFileA(findBuffer, &findFileData);
    if (hFind == INVALID_HANDLE_VALUE){
        PrintLastError(GetLastError());
        return;
    }
    char *pFileName = findFileData.cFileName;

    while (FindNextFileA(hFind, &findFileData))
    {
        if (0 != _stricmp(pFileName, "..") && 0 != _stricmp(pFileName, "."))
        {
            FileNod* pFileNod = (FileNod*)pQueue->obtain();
            //pFileNod->path = new char[strlen(pFileName)+1];
            pFileNod->setPath(pFileName);
            pQueue->linkLast(pFileNod);
            pFileNod->size = findFileData.nFileSizeLow;
            if (findFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
            {
                pFileNod->mode = 1;
                sprintf_s(findBuffer, "%s%s\\", path, findFileData.cFileName);
                show_file(findBuffer, pQueue, level + 1);
            }
        }
    }
}

#include<iostream>
using namespace std;

class Base
{
public:
    void fptr()
    {
        printf("void Base::fptr()\n");
    }
    virtual void vfptr()
    {
        printf("virtual void Base::vfptr()\n");
    }

    void fptr_arg(int i)
    {
        printf("void Base::fptr_arg(int i = %d)\n", i);
    }
    void fptr_arg2(int i)
    {
        printf("void Base::fptr_arg2(int i = %d)\n", i);
    }
    virtual void vfptr_arg(int i)
    {
        printf("virtual void Base::vfptr_arg(int i = %d)\n", i);
    }
    virtual void vfptr_arg2(int i)
    {
        printf("virtual void Base::vfptr_arg2(int i = %d)\n", i);
    }
    virtual void vfptr_arg3(int i)    //派生类没有此同名函数
    {
        printf("virtual void Base::vfptr_arg2(int i = %d)\n", i);
    }
};
class Derived : public Base
{
public:
    void fptr()//隐藏-覆盖
    {
        printf("void Derived::fptr()\n");
    }
    void vfptr()//隐藏-多态、覆盖
    {
        printf("virtual void Derived::vfptr()\n");
    }

    void fptr_arg(int i)//隐藏(同参)-覆盖(2)    
    {
        printf("void Derived::fptr_arg(int i = %d)\n", i);
    }
    void fptr_arg2(float f)//隐藏(不同参)-覆盖(1)由于继承类隐藏基类方法fptr_arg2(float),写代码时调不到基类同名方法的
    {
        printf("void Derived::fptr_arg2(float f = %f)\n", f);
    }
    virtual void vfptr_arg(int i)//隐藏(同参)-覆盖,会表现为运行时多态
    {
        printf("virtual void Derived::vfptr_arg(int i = %d)\n", i);
    }

    virtual void vfptr_arg2(float f)//隐藏(不同参)-覆盖,不会表现为运行时多态 (1)由于继承类隐藏基类方法vfptr_arg2(int),写代码时调不到基类同名方法的
    {
        printf("virtual void Derived::vfptr_arg2(float f = %f)\n", f);
    }

};


int _tmain(int argc, _TCHAR* argv[]) {
    {
        //如果应用程序有多个退出点,并不需要在每个退出点都手动设置一个对 _CrtDumpMemoryLeaks 的调用。 
        //应用程序开头部分对 _CrtSetDbgFlag 的调用会导致在每个退出点自动调用 _CrtDumpMemoryLeaks。 
        //您必须设置两个位域,如下所示:
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
        //new FileNod();
        char* scanPath = "D:\\BaiduYunDownload\\";
        printf("RecyledQueue queue(new FileNod())\n");
        RecyledQueue queue(FileNod::newNod0);
        //RecyledQueue queue(new FileNod());
        printf("\n\n//-----------show_file starts.-----------\n");
        show_file(scanPath, &queue);
        printf("\n//-----------show_file ends.-----------\n\n\n");
        FileNod *visitNode = (FileNod *)queue.header;
        FileNod *lastNode = NULL;
        FileNod *nextNode = NULL;
        int i = 0;

        while (visitNode) {
            nextNode = (FileNod *)visitNode->next;
            printf("%d : %s, %s, %d\n", i++, visitNode->path, (visitNode->mode ? "[Folder]" : "[File]"), visitNode->size);
            queue.unlinkFirst();
            visitNode = (FileNod *)nextNode;
        }


        i = 0;
        visitNode = (FileNod *)queue.recyledPool;

        printf("\n\n\n//------------------------------------------------\n\n\n");

        while (visitNode) {
            printf("%d : %s, %s, %d\n", i++, visitNode->path, (visitNode->mode ? "[Folder]" : "[File]"), visitNode->size);
            visitNode = (FileNod *)visitNode->next;
        }
    }//Esape queue  ~RecyledQueue().
    _CrtDumpMemoryLeaks();
    printf("\n\n\n//------------------------------------------------\n\n\n");
    Base a;
    Derived b;

    printf("----Base *p = &a; //ok------------------------------------\n");
    Base *p = &a;
    p->fptr();    //void A::fptr()
    p->vfptr();  //virtual void A::vfptr()

    printf("----Base *p = &b; //ok------------------------------------\n");
    p = &b;
    p->fptr();    //void A::fptr()    
    p->vfptr();  //virtual void B::vfptr()

    printf("----Derived *ptr = (Derived *)&a; //cast nosecury------------------------\n");
    Derived *ptr = (Derived *)&a;
    ptr->fptr();       //void B::fptr()    
    ptr->vfptr();  //virtual void A::vfptr()


    //C++的隐藏 “隐藏”是指派生类的函数屏蔽了与其同名的基类函数
    //(1)    如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆),即编译时符合基类参数而不符合派生类参数会报错。
    //(2)    如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
    
    //C++多态性
    //a、编译时多态性:通过重载函数实现 
    //b、运行时多态性:通过虚函数实现。即,条件:函数同名同参和带有关键字virtual。

    //无virtual关键字,编译时确定,根据指针类型。
    //有virtual关键字,运行时确定,根据指针指向的实际内容类型。
    //参数不同算重载
    printf("\n\n----Derived d; Base *pb = &d; Derived *pd = &d;---------------\n\n");
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
    // Good : behavior depends solely on type of the object  
    pb->fptr_arg(3.14f);   // void Base::fptr_arg(int i = 3)
    pd->fptr_arg(3.14f);   // void Derived::fptr_arg(int i = 3)
    pb->fptr_arg(3);   // void Base::fptr_arg(int i = 3)
    pd->fptr_arg(3);   // void Derived::fptr_arg(int i = 3)    

    printf("\n");

    // Bad : behavior depends on type of the pointer  
    pb->fptr_arg2(3.14f);   // void Base::fptr_arg2(int i = 3)
    pd->fptr_arg2(3.14f);   // void Derived::fptr_arg2(float f = 3.140000)
    pb->fptr_arg2(3);        // void Base::fptr_arg2(int i = 3)
    pd->fptr_arg2(3);        // void Derived::fptr_arg2(float f = 3.000000)

    printf("\n");

    // Bad : behavior depends on type of the pointer  
    pb->vfptr_arg(3.14f);   // virtual void Derived::vfptr_arg(int i = 3)
    pd->vfptr_arg(3.14f);   // virtual void Derived::vfptr_arg(int i = 3)
    pb->vfptr_arg(3);   // virtual void Derived::vfptr_arg(int i = 3)
    pd->vfptr_arg(3);   // virtual void Derived::vfptr_arg(int i = 3)

    printf("\n");

    // 
    pb->vfptr_arg2(3.14f);   // virtual void Base::vfptr_arg2(int i = 3)
    pd->vfptr_arg2(3.14f);   // virtual void Derived::vfptr_arg2(float f = 3.140000)
    pb->vfptr_arg2(3);         // virtual void Base::vfptr_arg2(int i = 3)
    pd->vfptr_arg2(3);         // virtual void Derived::vfptr_arg2(float f = 3.000000)
    pd->vfptr_arg3(3);         // 未被派生类隐藏

    getchar();
    return 0;

}

 

 

反汇编代码

可回收重复使用的链表,类似于Android消息链(并记录多态使用),,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。