动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > C/C++教程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ C/C++教程 ]的信息

本月文章推荐
.深度探索C++对象模型(5).
.C语言库函数 (C类字母).
.新设想——VC开发多语言界面支持.
.开发自己的英文语音朗读软件.
.C++入门解惑——初探指针.
.Windows编程基础 - 概.
.C语言入门之结构(1).
.C++面向对象编程入门:类(class).
.TCP/IP网络重复型服务器通信软件.
.一个四舍五入函数.
.获取当前鼠标位置的类名和句柄.
.C语言入门之分支结构(2).
.学习C++的最大难度是什么?.
.我的最爱.
.C语言实型数据.
.约瑟夫环C语言.
.水滴石穿C语言之可变参数问题.
.舍弃浮躁, 50条重要的C++学习建议.
.只需一分钟!设计漂亮的程序界面.
.学习c++的50条忠告(初学者必看).

教您在C/C++中如何构造通用的对象链表

发表日期:2008-3-8 |



  一个简化的问题示例

链表的难点在于必须复制链表处理函数来处理不同的对象,即便逻辑是完全相同的。例如两个结构类似的链表:

strUCt Struct_Object_A { int a; int b; Struct_Object_A *next; } OBJECT_A; typedef struct Struct_Object_B { int a; int b; int c; Struct_Object_B *next; } OBJECT_B; 


上面定义的两个结构只有很小的一点差别。OBJECT_B 和 OBJECT_A 之间只差一个整型变量。但是,在编译器看来,它们仍然是非常不同的。必须为存储在链表中的每个对象复制用来添加、删除和搜索链表的函数。为了解决这个问题,可以使用具有全部三个变量的一个联合或结构,其中整数 c 并不是在所有的情况下都要使用。这可能变得非常复杂,并会形成不良的编程风格。

C 代码解决方案:虚拟链表

此问题更好的解决方案之一是虚拟链表。虚拟链表是只包含链表指针的链表。对象存储在链表结构背后。这一点是这样实现的,首先为链表节点分配内存,接着为对象分配内存,然后将这块内存分配给链表节点指针,如下所示:

虚拟链表结构的一种实现

typedef struct liststruct { liststruct *next; } LIST, *pLIST; pLIST Head = NULL; pLIST AddToList( pLIST Head, void * data, size_t datasize ) { pLIST newlist=NULL; void *p; // 分配节点内存和数据内存 newlist = (pLIST) malloc ( datasize + sizeof( LIST ) ); // 为这块数据缓冲区指定一个指针 p = (void *)( newlist + 1 ); // 复制数据 memcpy( p, data, datasize ); // 将这个节点指定给链表的表头 if( Head ) { newlist->next = Head; } else newlist->next = NULL; Head = newlist; return Head; }


链表节点现在建立在数据值副本的基本之上。这个版本能很好地处理标量值,但不能处理带有用 malloc 或 new 分配的元素的对象。要处理这些对象,LIST 结构需要包含一个一般的解除函数指针,这个指针可用来在将节点从链表中删除并解除它之前释放内存(或者关闭文件,或者调用关闭方法)。

一个带有解除函数的链表

typedef void (*ListNodeDestructor)( void * ); typedef struct liststruct { ListNodeDestructor DestructFunc; liststruct *next; } LIST, *pLIST; pLIST AddToList( pLIST Head, void * data, size_t datasize, ListNodeDestructor Destructor ) { pLIST newlist=NULL; void *p; // 分配节点内存和数据内存 newlist = (pLIST) malloc ( datasize + sizeof( LIST ) ); // 为这块数据缓冲区指定一个指针 p = (void *)( newlist + 1 ); // 复制数据 memcpy( p, data, datasize ); newlist->DestructFunc = Destructor; // 将这个节点指定给链表的表头 if( Head ) { newlist->next = Head; } else newlist->next = NULL; Head = newlist; return Head; } void DeleteList( pLIST Head ) { pLIST Next; while( Head ) { Next = Head->next; Head->DestructFunc( (void *) Head ); free( Head ); Head = Next; } } typedef struct ListDataStruct { LPSTR p;
} LIST_DATA, *pLIST_DATA; void ListDataDestructor( void *p ) { // 对节点指针进行类型转换 pLIST pl = (pLIST)p; // 对数据指针进行类型转换 pLIST_DATA pLD = (pLIST_DATA) ( pl + 1 ); delete pLD->p; } pLIST Head = NULL; void TestList() { pLIST_DATA d = new LIST_DATA; d->p = new char[24]; strcpy( d->p, "Hello" ); Head = AddToList( Head, (void *) d, sizeof( pLIST_DATA ), ListDataDestructor ); // 该对象已被复制,现在删除原来的对象 delete d; d = new LIST_DATA; d->p = new char[24]; strcpy( d->p, "World" ); Head = AddToList( Head, (void *) d, sizeof( pLIST_DATA ), ListDataDestructor ); delete d; // 释放链表 DeleteList( Head ); } 


在每个链表节点中包含同一个解除函数的同一个指针似乎是浪费内存空间。确实如此,但只有链表始终包含相同的对象才属于这种情况。按这种方式编写链表答应您将任何对象放在链表中的任何位置。大多数链表函数要求对象总是相同的类型或类。

虚拟链表则无此要求。它所需要的只是将对象彼此区分开的一种方法。要实现这一点,您既可以检测解除函数指针的值,也可以在链表中所用的全部结构前添加一个类型值并对它进行检测。

当然,假如要将链表编写为一个 C++ 类,则对指向解除函数的指针的设置和存储只能进行一次。

C++ 解决方案:类链表

本解决方案将 CList 类定义为从 LIST 结构导出的一个类,它通过存储解除函数的单个值来处理单个存储类型。请注重添加的 GetCurrentData() 函数,该函数完成从链表节点指针到数据偏移指针的数学转换。一个虚拟链表对象

// 定义解除函数指针 typedef void (*ListNodeDestructor) ( void * ); // 未添加解除函数指针的链表 typedef struct ndliststruct { ndliststruct *next; } ND_LIST, *pND_LIST; // 定义处理一种数据类型的链表类 class CList : public ND_LIST { public: CList(ListNodeDestructor); ~CList(); pND_LIST AddToList ( void * data, size_t datasize ); void *GetCurrentData(); void DeleteList( pND_LIST Head ); private: pND_LIST m_HeadOfList; pND_LIST m_CurrentNode; ListNodeDestructor m_DestructFunc; }; // 用正确的起始值构造这个链表对象 CList::CList(ListNodeDestructor Destructor) : m_HeadOfList(NULL), m_CurrentNode(NULL) { m_DestructFunc = Destructor; } // 在解除对象以后删除链表 CList::~CList() { DeleteList(m_HeadOfList); } // 向链表中添加一个新节点 pND_LIST CList::AddToList ( void * data, size_t datasize ) { pND_LIST newlist=NULL; void *p; // 分配节点内存和数据内存 newlist = (pND_LIST) malloc ( datasize + sizeof( ND_LIST ) ); // 为这块数据缓冲区指定一个指针 p = (void *)( newlist + 1 ); // 复制数据 memcpy( p, data, datasize ); // 将这个节点指定给链表的表头 if( m_HeadOfList ) { newlist->next = m_HeadOfList; } else newlist->next = NULL; m_HeadOfList = newlist; return m_HeadOfList; } // 将当前的节点数据作为 void 类型返回, 以便调用函数能够将它转换为任何类型 void * CList::GetCurrentData() { return (void *)(m_CurrentNode+1); } // 删除已分配的链表 void CList::DeleteList( pND_LIST Head ) { pND_LIST Next; while( Head ) { Next = Head->next; m_DestructFunc( (void *) Head ); free( Head ); Head = Next; } } // 创建一个要在链表中创建和存储的结构 typedef struct ListDataStruct { LPSTR p;
} LIST_DATA, *pND_LIST_DATA; // 定义标准解除函数 void ClassListDataDestructor( void *p ) { // 对节点指针进行类型转换 pND_LIST pl = (pND_LIST)p; // 对数据指针进行类型转换 pND_LIST_DATA pLD = (pND_LIST_DATA) ( pl + 1 ); delete pLD->p; } // 测试上面的代码 void MyCListClassTest() { // 创建链表类 CList* pA_List_of_Data = new CList(ClassListDataDestructor); // 创建数据对象 pND_LIST_DATA d = new LIST_DATA; d->p = new char[24]; strcpy( d->p, "Hello" ); // 创建
上一篇:教学计划编制问题 人气:437
下一篇:进制的转换 人气:392
浏览全部C/C++的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-8-20 OA企业智能办公自动化系统边缘特
2008-8-19 久溜溜电影系统(免维护+小偷) v5
2008-8-19 晴天免费电影系统完整版(带迅雷采
2008-8-19 Twinklous File Manager v1.5
2008-8-19 千米旅游网站管理系统 v2.0
2008-8-19 资阳人才网 v2.0
2008-8-19 全球商务B2B网站系统 v1.0 asp版
2008-8-19 动域网主机代理管理系统 v1.0
2008-8-19 JH2008-企业网站(全站生成html)
2008-8-16 iLaba Player(小喇叭播放器) v2.
2008-8-16 DoubleClickFix 鼠标双击修正工具
2008-8-16 CrystalCPUID 4.15.2.451
2008-8-16 VeryCD 电驴(easyMule) 1.0.4 Bu
2008-8-16 uTorrent 1.8 Build 11813 - Sta
2008-8-16 比特精灵(BitSpirit) v3.3.2.287
2008-8-16 StayInTune音叉 v1.0 破解版
2008-8-16 iChing《周易》汉化补丁 v1.0
2008-8-16 Starmap星空图v1.0汉化破解版
  发表评论
姓 名: 验证码:
内 容:
[ 汉字翻译拼音 ] [ 广告代码 ] [ 符号对照表 ] [ 进制转换 ] [ 经典小工具 ] [ 个税计算 ] [ 汉字简繁转换 ] [ 普通单位换算 ] [ 公制单位换算 ]
[ 生辰老黄历 ] [ 国内电话区号 ] [ 国家代码与域名缩写 ] [ 文字加密解密 ] [ 健康查询 ] [ 万年历 ] [ 手机号码查询 ] [ ip搜索 ] [ Google PR查询 ]
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵