linux社区爱心援助Linux认证系列教程业界动态站务新闻公司招聘建议留言网址大全LPI专题CISCO专题
设为首页
加入收藏
管理团队
JSP  
JAVA  
PERL  
 您的位置:首页 > article > Linux开发区 > 软件开发 >
栏目导栏
资料搜索
热门文章
·Linux 下 C 语言编程
·Linux下的通用线程池创建
·C++字符串转换篇
·linux C 进程操作篇
·linux上的C/C++编译器gcc/egcs
·linux C 文件权限控制篇
·GCC使用手册
·linux C 接口处理篇
·在Redhat Linux上安装 GCC 编译
·GCC使用指南
·C语言运算符
·Linux下C开发环境的构成和安装
·fopen()函数的参数说明
·GCC使用手册与常用命令
·Scheme 语言介绍
最新文章
·在Ubuntu Linux 8.04上构建GCC
·Linux操作系统下Socket编程地址
·将VC程序移植到Linux系统的几点
·Linux下malloc/free与new/dele
·Linux下用GTK和socket实现简单
·Linux操作系统下让Tomcat启动在
·Linux操作系统中如何编译C程序
·几种常被人们忽略的Linux系统下
·Eclipse编程工具 在Ubuntu下的
·Linux操作系统下的网络地址转换
·老手经验谈:Linux驱动程序开发
·Linux操作系统多线程同步Mutex
·Linux操作系统下C程序语言简易
·Linux系统平台下关于GCC编译及
·解决Linux系统下管道被接受方关
Google
 
在C/C++中如何构造通用的对象链表
[ 作者:  加入时间:2007-06-13 17:08:09  来自:Linux联盟收集整理 ]
一个简化的问题示例W2jLinux联盟
  链表的难点在于必须复制链表处理函数来处理不同的对象,即便逻辑是完全相同的。例如:W2jLinux联盟
  W2jLinux联盟
  两个结构类似的链表W2jLinux联盟
  struct Struct_Object_AW2jLinux联盟
  {W2jLinux联盟
    int a;W2jLinux联盟
    int b;W2jLinux联盟
    Struct_Object_A *next;W2jLinux联盟
  W2jLinux联盟
  } OBJECT_A;W2jLinux联盟
  W2jLinux联盟
  typedef struct Struct_Object_BW2jLinux联盟
  {W2jLinux联盟
    int a;W2jLinux联盟
    int b;W2jLinux联盟
    int c;W2jLinux联盟
    Struct_Object_B *next;W2jLinux联盟
  W2jLinux联盟
  } OBJECT_B;    W2jLinux联盟
   上面定义的两个结构只有很小的一点差别。OBJECT_B 和 OBJECT_A 之间只差一个整型变量。但是,在编译器看来,它们仍然是非常不同的。必须为存储在链表中的每个对象复制用来添加、删除和搜索链表的函数。为了解决这个问 题,可以使用具有全部三个变量的一个联合或结构,其中整数 c 并不是在所有的情况下都要使用。这可能变得非常复杂,并会形成不良的编程风格。W2jLinux联盟
  W2jLinux联盟
  C 代码解决方案:虚拟链表W2jLinux联盟
  此问题更好的解决方案之一是虚拟链表。虚拟链表是只包含链表指针的链表。对象存储在链表结构背后。这一点是这样实现的,首先为链表节点分配内存,接着为对象分配内存,然后将这块内存分配给链表节点指针,如下所示:W2jLinux联盟
  W2jLinux联盟
  虚拟链表结构的一种实现W2jLinux联盟
  typedef struct liststructW2jLinux联盟
  {W2jLinux联盟
    liststruct *next;W2jLinux联盟
  W2jLinux联盟
  } LIST, *pLIST;W2jLinux联盟
  W2jLinux联盟
  pLIST Head = NULL;W2jLinux联盟
  W2jLinux联盟
  pLIST AddToList( pLIST Head, void * data, size_t datasize )W2jLinux联盟
  {W2jLinux联盟
  pLIST newlist=NULL;W2jLinux联盟
  void *p;W2jLinux联盟
  W2jLinux联盟
    // 分配节点内存和数据内存W2jLinux联盟
    newlist = (pLIST) malloc( datasize + sizeof( LIST ) );W2jLinux联盟
  W2jLinux联盟
    // 为这块数据缓冲区指定一个指针W2jLinux联盟
    p = (void *)( newlist + 1 );W2jLinux联盟
  W2jLinux联盟
    // 复制数据W2jLinux联盟
    memcpy( p, data, datasize );W2jLinux联盟
  W2jLinux联盟
    // 将这个节点指定给链表的表头W2jLinux联盟
    if( Head )W2jLinux联盟
    {W2jLinux联盟
    newlist->next = Head;W2jLinux联盟
    }W2jLinux联盟
    elseW2jLinux联盟
    newlist->next = NULL;W2jLinux联盟
  W2jLinux联盟
    Head = newlist;W2jLinux联盟
  W2jLinux联盟
    return Head;W2jLinux联盟
  }    W2jLinux联盟
   链表节点现在建立在数据值副本的基本之上。这个版本能很好地处理标量值,但不能处理带有用 malloc 或 new 分配的元素的对象。要处理这些对象,LIST 结构需要包含一个一般的解除函数指针,这个指针可用来在将节点从链表中删除并解除它之前释放内存(或者关闭文件,或者调用关闭方法)。W2jLinux联盟
  W2jLinux联盟
  一个带有解除函数的链表W2jLinux联盟
  typedef void (*ListNodeDestructor)( void * );W2jLinux联盟
  W2jLinux联盟
  typedef struct liststructW2jLinux联盟
  {W2jLinux联盟
    ListNodeDestructor DestructFunc;W2jLinux联盟
    liststruct *next;W2jLinux联盟
  W2jLinux联盟
  } LIST, *pLIST;W2jLinux联盟
  W2jLinux联盟
  pLIST AddToList( pLIST Head, void * data, size_t datasize,W2jLinux联盟
  ListNodeDestructor Destructor )W2jLinux联盟
  {W2jLinux联盟
  pLIST newlist=NULL;W2jLinux联盟
  void *p;W2jLinux联盟
  W2jLinux联盟
  W2jLinux联盟
    // 分配节点内存和数据内存W2jLinux联盟
    newlist = (pLIST) malloc( datasize + sizeof( LIST ) );W2jLinux联盟
  W2jLinux联盟
    // 为这块数据缓冲区指定一个指针W2jLinux联盟
    p = (void *)( newlist + 1 );W2jLinux联盟
  W2jLinux联盟
    // 复制数据W2jLinux联盟
    memcpy( p, data, datasize );W2jLinux联盟
  W2jLinux联盟
    newlist->DestructFunc = Destructor;W2jLinux联盟
    W2jLinux联盟
    // 将这个节点指定给链表的表头W2jLinux联盟
    if( Head )W2jLinux联盟
    {W2jLinux联盟
      newlist->next = Head;W2jLinux联盟
    }W2jLinux联盟
    elseW2jLinux联盟
      newlist->next = NULL;W2jLinux联盟
  W2jLinux联盟
    Head = newlist;W2jLinux联盟
  W2jLinux联盟
    return Head;W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  void DeleteList( pLIST Head )W2jLinux联盟
  {W2jLinux联盟
    pLIST Next;W2jLinux联盟
    while( Head )W2jLinux联盟
    {W2jLinux联盟
      Next = Head->next;W2jLinux联盟
      Head->DestructFunc( (void *) Head );W2jLinux联盟
      free( Head );W2jLinux联盟
      Head = Next;W2jLinux联盟
    }W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  typedef struct ListDataStructW2jLinux联盟
  {W2jLinux联盟
    LPSTR p;W2jLinux联盟
  W2jLinux联盟
  } LIST_DATA, *pLIST_DATA;W2jLinux联盟
  W2jLinux联盟
  void ListDataDestructor( void *p )W2jLinux联盟
  {W2jLinux联盟
    // 对节点指针进行类型转换W2jLinux联盟
    pLIST pl = (pLIST)p;W2jLinux联盟
  W2jLinux联盟
    // 对数据指针进行类型转换W2jLinux联盟
    pLIST_DATA pLD = (pLIST_DATA) ( pl + 1 );W2jLinux联盟
  W2jLinux联盟
    delete pLD->p;W2jLinux联盟
  }W2jLinux联盟
  pLIST Head = NULL;W2jLinux联盟
  W2jLinux联盟
  void TestList()W2jLinux联盟
  {W2jLinux联盟
    pLIST_DATA d = new LIST_DATA;W2jLinux联盟
    d->p = new char[24];W2jLinux联盟
    strcpy( d->p, "Hello" ); W2jLinux联盟
    Head = AddToList( Head, (void *) d, sizeof( pLIST_DATA ),W2jLinux联盟
    ListDataDestructor );W2jLinux联盟
    // 该对象已被复制,现在删除原来的对象W2jLinux联盟
    delete d;W2jLinux联盟
  W2jLinux联盟
    d = new LIST_DATA;W2jLinux联盟
    d->p = new char[24];W2jLinux联盟
    strcpy( d->p, "World" ); W2jLinux联盟
    Head = AddToList( Head, (void *) d, sizeof( pLIST_DATA ),W2jLinux联盟
    ListDataDestructor );W2jLinux联盟
    delete d;W2jLinux联盟
  W2jLinux联盟
    // 释放链表W2jLinux联盟
    DeleteList( Head );W2jLinux联盟
  }    W2jLinux联盟
   在每个链表节点中包含同一个解除函数的同一个指针似乎是浪费内存空间。确实如此,但只有链表始终包含相同的对象才属于这种情况。按这种方式编写链表允许 您将任何对象放在链表中的任何位置。大多数链表函数要求对象总是相同的类型或类。虚拟链表则无此要求。它所需要的只是将对象彼此区分开的一种方法。要实现 这一点,您既可以检测解除函数指针的值,也可以在链表中所用的全部结构前添加一个类型值并对它进行检测。当然,如果要将链表编写为一个 C++ 类,则对指向解除函数的指针的设置和存储只能进行一次。W2jLinux联盟
  W2jLinux联盟
  C++ 解决方案:类链表W2jLinux联盟
  本解决方案将 CList 类定义为从 LIST 结构导出的一个类,它通过存储解除函数的单个值来处理单个存储类型。请注意添加的 GetCurrentData() 函数,该函数完成从链表节点指针到数据偏移指针的数学转换。W2jLinux联盟
  W2jLinux联盟
  一个虚拟链表对象W2jLinux联盟
  W2jLinux联盟
  W2jLinux联盟
  // 定义解除函数指针W2jLinux联盟
  W2jLinux联盟
  typedef void (*ListNodeDestructor)( void * );W2jLinux联盟
  W2jLinux联盟
  // 未添加解除函数指针的链表W2jLinux联盟
  W2jLinux联盟
  typedef struct ndliststructW2jLinux联盟
  {W2jLinux联盟
    ndliststruct *next;W2jLinux联盟
  W2jLinux联盟
  } ND_LIST, *pND_LIST;W2jLinux联盟
  W2jLinux联盟
  // 定义处理一种数据类型的链表类W2jLinux联盟
  W2jLinux联盟
  class CList : public ND_LISTW2jLinux联盟
  {W2jLinux联盟
  public:W2jLinux联盟
    CList(ListNodeDestructor);W2jLinux联盟
    ~CList();W2jLinux联盟
    pND_LIST AddToList( void * data, size_t datasize );W2jLinux联盟
    void *GetCurrentData();W2jLinux联盟
    void DeleteList( pND_LIST Head );W2jLinux联盟
  W2jLinux联盟
  W2jLinux联盟
  private:W2jLinux联盟
    pND_LIST m_HeadOfList;W2jLinux联盟
    pND_LIST m_CurrentNode;W2jLinux联盟
    ListNodeDestructor m_DestructFunc;W2jLinux联盟
  };W2jLinux联盟
  W2jLinux联盟
  // 用正确的起始值构造这个链表对象W2jLinux联盟
  W2jLinux联盟
  CList::CList(ListNodeDestructor Destructor)W2jLinux联盟
    : m_HeadOfList(NULL), m_CurrentNode(NULL)W2jLinux联盟
  {W2jLinux联盟
    m_DestructFunc = Destructor;W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  // 在解除对象以后删除链表W2jLinux联盟
  W2jLinux联盟
  CList::~CList()W2jLinux联盟
  {W2jLinux联盟
    DeleteList(m_HeadOfList);W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  // 向链表中添加一个新节点W2jLinux联盟
  W2jLinux联盟
  pND_LIST CList::AddToList( void * data, size_t datasize )W2jLinux联盟
  {W2jLinux联盟
  pND_LIST newlist=NULL;W2jLinux联盟
  void *p;W2jLinux联盟
  W2jLinux联盟
  W2jLinux联盟
    // 分配节点内存和数据内存W2jLinux联盟
    newlist = (pND_LIST) malloc( datasize + sizeof( ND_LIST ) );W2jLinux联盟
  W2jLinux联盟
    // 为这块数据缓冲区指定一个指针W2jLinux联盟
    p = (void *)( newlist + 1 );W2jLinux联盟
  W2jLinux联盟
    // 复制数据W2jLinux联盟
    memcpy( p, data, datasize );W2jLinux联盟
  W2jLinux联盟
    // 将这个节点指定给链表的表头W2jLinux联盟
    if( m_HeadOfList )W2jLinux联盟
    {W2jLinux联盟
      newlist->next = m_HeadOfList;W2jLinux联盟
    }W2jLinux联盟
    elseW2jLinux联盟
      newlist->next = NULL;W2jLinux联盟
  W2jLinux联盟
    m_HeadOfList = newlist;W2jLinux联盟
  W2jLinux联盟
    return m_HeadOfList;W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  // 将当前的节点数据作为 void 类型返回,以便调用函数能够将它转换为任何类型W2jLinux联盟
  W2jLinux联盟
  void * CList::GetCurrentData()W2jLinux联盟
  {W2jLinux联盟
    return (void *)(m_CurrentNode+1);W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  // 删除已分配的链表W2jLinux联盟
  W2jLinux联盟
  void CList::DeleteList( pND_LIST Head )W2jLinux联盟
  {W2jLinux联盟
    pND_LIST Next;W2jLinux联盟
    while( Head )W2jLinux联盟
    {W2jLinux联盟
      Next = Head->next;W2jLinux联盟
      m_DestructFunc( (void *) Head );W2jLinux联盟
      free( Head );W2jLinux联盟
      Head = Next;W2jLinux联盟
    }W2jLinux联盟
  }W2jLinux联盟
  W2jLinux联盟
  // 创建一个要在链表中创建和存储的结构W2jLinux联盟
  W2jLinux联盟
  typedef struct ListDataStructW2jLinux联盟
  {W2jLinux联盟
    LPSTR p;W2jLinux联盟
  W2jLinux联盟
  } LIST_DATA, *pND_LIST_DATA;W2jLinux联盟
  W2jLinux联盟
  // 定义标准解除函数W2jLinux联盟
  W2jLinux联盟
  void ClassListDataDestructor( void *p )W2jLinux联盟
  {W2jLinux联盟
    // 对节点指针进行类型转换W2jLinux联盟
    pND_LIST pl = (pND_LIST)p;W2jLinux联盟
  W2jLinux联盟
  
Linux联盟收集整理 ,转贴请标明原始链接,如有任何疑问欢迎来本站Linux论坛讨论
评论】【加入收藏夹】【 】【打印】【关闭
※ 相关链接
 ·在 C/C++中如何构造通用的对象链表  (2006-12-26 11:33:40)