您的位置:软件 > 开发者网络 > 开发工具 > 开发专栏 > C/C++ > 正文
利用C++模板编写的序列化框架
[文章信息]
作者:潘凯
时间:2005-01-22
出处:VCHELP
责任编辑:方舟
[文章导读]
在这个框架中包含了一个序列化的基本框架,一套基本的类型识别系统
advertisement
热点推荐
· 迷你迅雷给IE下载加足马力
· 《大话李白》主题曲 Flash
· Windows操作系统小技巧荟萃(上)
· 新浪UC2005使用技巧四则
· Google 2秒钟搜索100G硬盘
[正文]
  简介

  在这个框架中包含了一个序列化的基本框架,一套基本的类型识别系统,可以识别基础类型,复杂类型,自定义类型,STD的容器类型,而且可以这个基础上进行递归的扩展。

  可以将复杂的数据结构序列化到文件,并从文件中恢复。

  包含了完整的自动单元测试,和测试案例,点此下载

  正文

  写这个序列化框架最初是想用在一个大型的项目上,在那个项目中有一些相当复杂的在运行时构建出来的树形数据结构,如果可以将这个内存树序列化起来可以大大节约下次创建的时间。另外在自己做的一些小工具中,有些数据想保存在文件中,以后再从文件中读取,用序列化的方式也十分方便。而且那时正好系统的学习了一下C++模板技术,感觉在一般的编程活动中很难用到一些比较高级的模板技术,所以想用C++模板技术来写这个序列化框架。最后那个项目中没有使用这个序列化框架,但我至少达到了第二个目标,写这个序列化框架让我对C++模板技术有了更深层次的理解。

  在这个框架中包含了一个序列化的基本框架,一套基本的类型识别系统,可以识别基础类型,复杂类型,自定义类型,STD的容器类型,而且可以这个基础上进行递归的扩展。

  在写这个框架的同时,我也写了完整的测试案例。如果没有测试案例,要调试这样的框架可就真是难与登天,因为模板方面的错误,编译器报出来的信息很难看,有的根本就没用。

  代码是在VC7.1下写的,也只能在VC7.1下用,VC6对于C++模板的支持非常有限,而其他的编译器在这方面的支持也有出入。如果要用于其他的编译器可能要修改部分类型识别方面的代码。测试框架我用的是cppunit(1.9.14),这是个开源的测试框架,可以在www.xprogramming.com下载到。其中类型识别方面的代码我主要是参考了《C++ template》一书,和boost中的部分代码。

  由于是用模板写的比MFC中的运行时序列化框架在效率上的表现要好得多。使用起来也相当的简单。如果要学习C++模板的高级技术,研究一下这个框架可以获益良多。由于是框架代码,我写得相当规范,有注释,也有完整的测试案例,可以进行自动的回归测试。

  使用的方法比较简单请参考(fileRWTest.cpp)文件中的测试案例。

  普通的数据类型:

(unsigned char, unsigned short, unsigned int, unsigned long, signed char, signed short, signed int, signed long, bool, char, wchar_t, unsigned long long, signed long long, float, double, long double)可以直接序列化及反序列化。

  对于指针类型:

  会序列化指针具体指向的对象,如果指针指向的对象的类型是序列化框架无法识别的类型会报出编译错误。注意在反序列化时,只需要传一个空指针即可,序列化框架会将被序列化的对象的值反序列化到堆上,并将地址付给指针。如果传一个有值的指针,在DEBUG模式下会在运行时引发一个断言错误。在RELEASE下会导致原来指针指向的对象被泄漏。

 
  对于普通数据类型的数组:

  会将整个数组以内存拷贝的方式序列化到内存,即使没被真正赋值的元素。反序列化时传一个相同类型的数组即可。需要注意的是,传进的数组的容量必须大于或等于被序列化的数组的容量,否则会引发数组越界的内存错误,在DEBUG模式下,会引发一个断言错误。

  非普通数据类型的数组:

  数组元素的类型可以是除普通数据类型之外的所有被序列化框架所支持的类型。序列化时会针对每一个元素调用序列化框架对它的具体序列化特化,反序列化时亦然。由于在RELEASE模式下类类型的数组在申明后,编译器会生成调用相应类的缺省构造函数的代码。但对于原始类型,如指针数组类型如果不显式的手工初始化,数组中的值是无意的随机值。这种情况序列化框架无法识别,会赞成严重的内存错误。另对于指针数组的某些元素为NULL的情况,序列化框架也无法处理,在DEBUG模式下会引发一个断言错误。

  因些如果是指针数组除非数组中的元素全部为有意义的指针,否则不应该做为一个数组来序列化,而应该加入相应的遍历逻辑,将有意思的元素逐个序列化。

  对于一般的数组,如果有意思的只是其中的少部分元素,也应该以上述方式进行序列化,以提高性能。

  自定义数据类类型:

  不需要拷贝构造函数,不需要拷贝赋值函数,不需要析构函数的类。如老式的struct结构类型。这种类型可以通过直接拷贝内存而被高效的序列化及化序列化。只需要让一个类从_data_class_tag派生,序列化框架就会将它当成普通的数据类类型处理。

  自定义复杂类型:

  对于非数据类类型,必须从CSerializable派生,关在类的定义中加入SERIALIZABLE(name, x)宏,name是该类的名字,x是相应的版本号。版本号的引入主要是避免在一个类被修改后,和以前生成的序列化文件一起使用,以免引起内存错误。在类中还必须实现virtual bool Serialize(CMedia *) const;函数,在该函数中写具体的序列化代码。该函数的内容很简单,按序列化及反序列化用为两段,简单的为每一个需要序列化及反序列化的成员函数调用即可,如下列:

if (pMedia->IsStoring()) {
 *pMedia << m_1 << m_2 << m_3 << m_4 << m_5;
 return true;
}
if (pMedia->IsLoading()) {
 *pMedia >> m_1 >> m_2 >> m_3 >> m_4 >> m_5;
 return true;
}

  注意序列化和反序列化的顺序这要错。

  std::string及std::wstring类型:

  使用比较简单。值得注意的是和将字符串数组做字符指针用的情况一样。如果申明了一个容量很大的string(一般是为了避免在追加时的内存重分配开销),却只用了一小部分。序列化并反序列化,string对象的容量只是刚好有内存的那部分。

  std::pair类型:

  只要是pair的first和second必须是序列化框架所支持的类型就可以被正常的序列化及反序列化。

  std容器类型:

(vector,list,deque,stack,queue,set,multiset,map,multimap)

  支持以上的容器类型,其中容器中的元素类型必须是序列化框架所支持的类型。




发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • C语言高效编程的的四大绝招
  • C++高质量编程点滴
  • C++中用vectors改进内存的再分配
  • C++中用函数模板实现和优化抽象操作
  • C++ 中重载 + 操作符的正确方法
  • 寄出钱易趣说没收到 网上购物“优惠”遭质疑
  • 内地C2C网站集体对接海外 扩展两岸三地市场
  • 企业信息化时代的新兴职业:客户关系管理师
  • 诺基亚光辉岂止区区15年 CEO奥利拉不信邪
  • CN域名注册价格大跳水 将与.COM域名持平
  • 中国将制定首个国家信息化战略 年底前发布
  • 04年中国企业十大新闻揭晓 联想收购列第一
  • 跨国公司在华兴独资浪潮 欧盟与日本打头阵
  • Advertisement

    天极无线


    奇妙科幻|美好风光|清风车影|漫画卡通|星座生肖|明星写真|动物世界
    老鼠爱大米
    挥着翅膀的女孩
    女人味
    栀子花开
    白月光
    刚刚好
    江南
    快乐崇拜
    亲爱的你怎么不在我身边
    小薇
    2002年的第一场雪
    有多少爱可以重来
    我的地盘
    七里香
    情人
     
    老鼠爱大米 老板电话
    冲动的惩罚 七里香
    我不是黄蓉 女生撒娇
    盛夏的果实 坚持到底
    孤单北半球 眉飞色舞
    挪威的森林 可爱女人
    最浪漫的事 老板电话

    CSEEK搜索