在尾部生产,头部消耗的链表,数据增加可重复使用的功能。
新数据类型继承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消息链(并记录多态使用),布布扣,bubuko.com
时间: 2024-10-14 23:14:07