网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
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,移动开发
本月文章推荐
.Visual Studio.Net 快捷键表.
.Visual C++中动态链接库技术浅谈.
.类——C++面向对象编程的基石.
.VC中利用人工智能解决八迷宫问题.
.用DEF文件从DLL中导出C++类.
.C++ Builder 创建并使.
.CGI编程的安全性 -- 文件名.
..
.猜拳.
.初级 WINDOWS API C++语言版 编程.
.在libxxx.a文件中如何查找函数.
.Borland有一个梦,程序员的梦.
.链表的c语言实现(七).
.水滴石穿C语言之C语言的底层操作.
.More Effective C++:类型转换.
.如何编写异常安全的C++代码.
.C语言中的位域的使用.
.C++程序设计最佳实践.
..
.C语言初学者入门讲座 第六讲 分支.

在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(voi
上一篇:在C++中处理错误的方法 人气:538
下一篇:在BCB中使用VCL控件数组2 人气:537
浏览全部C/C++的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐