C++通过操作内存模拟序列化---实现多种类型的序列化(2)

简介: 昨天晚上写了部分序列化,结果睡着了....今天继续完善.. 明天的四级反正是裸考了,无所谓了 。。。。 昨天写的那个只能实现单一类型的简单序列化 ,但是原理却是一样.. 今天这个可以实现不同的类的序列化,但是注意的一点是我们发现前天的序列化类实现了模板 .
昨天晚上写了部分序列化,结果睡着了....今天继续完善.. 明天的四级反正是裸考了,无所谓了 。。。。
昨天写的那个只能实现单一类型的简单序列化 ,但是原理却是一样..
今天这个可以实现不同的类的序列化,但是注意的一点是我们发现前天的序列化类实现了模板 ..可以正常的序列化反序列化 
如果我们将其抽象出来从一个基类派生,那么模板就显得不好处理了,这里最笨的方法使用到多重继承 实现多个基类.然后再将这些基类进行进一步的抽象成一个更高的基类.让我们的类从这个继承树最顶层继承,我不知道微软在MFC 和Sun在  java的对象流中是如何处理这些泛型类的 ...但是
如果像我上面这样处理泛型 ,可能需要写很多份代码...虽然说实际开发中对于模板的使用 泛型化参数不会很多 ,但是这样的问题总是需要一个更好的解决方案来处理各种情况 。  我是想不出来,求神解答。。。。
由于对于泛型化类的处理不是一时半刻能弄出来 ,下面我接着昨晚上的做 ,我这里只处理C++中的非泛化的类 ,或许哪天我就明白了 。。。
昨天  JXXXXXXXX提出说只能实现一个类.于是我修改了下 ,只要继承自Base的类都可以实现序列化 ......具体代码如下
还有的一点从文件---->内存--------->对象的恢复 没有构造函数的调用 ,这一点很神奇 。。。
我们成功的恢复了2个对象但是却没有发生构造函数的调用...之所以我这种序列化方式能成功 ,肯定是在编译器内部对于这种方式做了某种
支撑所以我说微软MFC的序列化方式可能是这种方式。。。

 

 

 图片

#include <iostream>
#include <fstream>
#include <string>
using  namespace std ;
class Base

public:
   /*  Base类型提供了统一的实现 ,所有需要序列化的类必须继承自Base类 包括成员对象
   *   LoadObject  LoadObject 在这里不需要多态机制 单独作为功能的实现
   *   length 为对象的实际长度 为了避免在内存重分配过多的内存浪费空间
   *   long length=sizeof(*obj) ;  //不可以这样做因为 我们发现实际上sizeof这个运算符
   *    在操作的时候获取的是当前运行时类型所指对象的大小 如果向上转型那么会进行窄化处理 获得的大小是1 所以这里要传递实际大小
   *   LoadObject  LoadObject作为Base的静态方法分别提供序列化和反序列化的功能
   */
    static void StoreObject(Base *obj,string file,int length)  
    {  
       cout<<"对象写入到文件..."<<endl ;
        ofstream *o=new ofstream(file.c_str()) ;
     o->write((char*)obj,length) ;
  o->close() ;
  delete o ;
    }
    static Base* LoadObject(string file,int length) 
  {
   cout<<"从文件恢复对象..."<<endl ; 
   if(Base::tem_object!=NULL)
      return Base::tem_object ;
         char *buf=new char[length] ;
      ifstream i(file.c_str()) ;
      i>>buf ;
      Base *p=(Base*)buf ;
   Base::tem_object=p ;
   i.close() ;
   return (p);
  }
 /*
 * 构造器用做一些初始化操作
 */
 Base()
 {
     
 cout<<"基类构造中..."<<endl; }
 /*
 *  释放反序列化时候分配的空间
 */
 virtual ~Base()
 {
  if(NULL==Base::tem_object)
   delete Base::tem_object ;
  Base::tem_object=NULL ;
 }
private:
 /*
 *  暂存加载的对象,对于同一个对象无论LoadObject多少次 加载的永远只是
 *  返回的同一份内存即同一个对象,直到这个对象的声明周期完毕,那么再次加载会是不同的对象
 */
  static Base *tem_object;
};
Base * Base::tem_object=NULL ;  //必须初始化静态指针
//序列化类Data
class Data  :public Base
{   
private :
 int data ;
public:
    Data(int x)
    {
 cout<<"Data构造中..."<<endl ;
 this->data=x;
    }
    void OutPut()
    {
     cout<<"Data.data="<<this->data<<endl ;
    }
} ;
//序列化类MyObject
class MyObject :public Base
{
public :
  MyObject(int x)
  {  
 cout<<"MyObject 构造中.."<<endl;
      this->x=x ;
  }
  ~MyObject()
  {
  }
 
  MyObject ShowX()  //一段最简单的代码
 {
  cout<<"x="<<x<<endl ;
  return (*this) ;
 }
private :
 int x ;
}  ;
int main()
{  
    string file1="c:\\data.txt" ;
    string file2="c:\\myobject.txt" ;
 int len1=sizeof(Data) ;
 int len2=sizeof(MyObject) ;
 /*
 *  序列化测试
 */
 //测试对象1 ...
    Data *d=new Data(8);
    Base::StoreObject(d,file1,len1) ;
 //测试对象2
 MyObject *obj=new MyObject(33) ;
 Base::StoreObject(obj,file2,len2) ;  
   
  /*
 *  反序列化测试。。
 */
 ((Data*)Base::LoadObject(file1,len1))->OutPut() ;
 ((MyObject*)Base::LoadObject(file2,len2))->ShowX()  ;

 delete d ;
 delete obj ;
 return 0 ;
}
操蛋的是睡觉之前出BUG了 ,明天要带着BUG裸考了 。。
BUG1    同时序列化 2个以上的对象  如果序列化和反序列化放在一起了 就像下面的代码
   Data *d=new Data(43);
    Base::StoreObject(d,file1,len1) ;
  MyObject *obj=new MyObject(13) ;
 Base::StoreObject(obj,file2,len2) ;
 ((Data*)Base::LoadObject(file1,len1))->OutPut() ;
 ((MyObject*)Base::LoadObject(file2,len2))->ShowX()  ;  
发现Data类的域中的x的值居然和MyObject类的成员数据是一样的 。。。 但是如果像下面这样一次处理一个 就不会有问题  。
  Data *d=new Data(43);
    Base::StoreObject(d,file1,len1) ;
 ((Data*)Base::LoadObject(file1,len1))->OutPut() ;
BUG2     如果先调用如下
  Data *d=new Data(43);
    Base::StoreObject(d,file1,len1) ;
然后把上述代码注释掉,在调用如下,在从文件加载 就会出现值的乱码 
 ((Data*)Base::LoadObject(file1,len1))->OutPut() ;
相反的 如果一次性把序列化和反序列化写在一起 ,那么即使下次调用多次也不会出问题,,,
算了考完试再继续Debug吧...哪位愿意帮忙调试下。。。
图片

 

 

目录
相关文章
|
1月前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
52 3
|
1月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
36 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
88 4
|
2月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
153 21
|
2月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
2月前
|
存储 C语言 C++
【C++打怪之路Lv6】-- 内存管理
【C++打怪之路Lv6】-- 内存管理
47 0
【C++打怪之路Lv6】-- 内存管理
|
2月前
|
存储 C语言 C++
【C/C++内存管理】——我与C++的不解之缘(六)
【C/C++内存管理】——我与C++的不解之缘(六)
|
2月前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
83 1
|
2月前
|
C++
C/C++内存管理(下)
C/C++内存管理(下)
52 0
|
2月前
|
存储 Linux C语言
C/C++内存管理(上)
C/C++内存管理(上)
42 0