昨天晚上写了部分序列化,结果睡着了....今天继续完善.. 明天的四级反正是裸考了,无所谓了 。。。。
昨天写的那个只能实现单一类型的简单序列化 ,但是原理却是一样..
今天这个可以实现不同的类的序列化,但是注意的一点是我们发现前天的序列化类实现了模板 ..可以正常的序列化反序列化
如果我们将其抽象出来从一个基类派生,那么模板就显得不好处理了,这里最笨的方法使用到多重继承 实现多个基类.然后再将这些基类进行进一步的抽象成一个更高的基类.让我们的类从这个继承树最顶层继承,我不知道微软在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 ;
#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 ;
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);
}
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 ; //必须初始化静态指针
* 构造器用做一些初始化操作
*/
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)
{
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 ;
}
} ;
}
void OutPut()
{
cout<<"Data.data="<<this->data<<endl ;
}
} ;
//序列化类MyObject
class MyObject :public Base
{
public :
MyObject(int x)
{
class MyObject :public Base
{
public :
MyObject(int x)
{
cout<<"MyObject 构造中.."<<endl;
this->x=x ;
}
~MyObject()
{
}
MyObject ShowX() //一段最简单的代码
{
cout<<"x="<<x<<endl ;
return (*this) ;
}
this->x=x ;
}
~MyObject()
{
}
MyObject ShowX() //一段最简单的代码
{
cout<<"x="<<x<<endl ;
return (*this) ;
}
private :
int x ;
} ;
int x ;
} ;
int main()
{
string file1="c:\\data.txt" ;
string file2="c:\\myobject.txt" ;
int len1=sizeof(Data) ;
int len2=sizeof(MyObject) ;
{
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() ;
* 序列化测试
*/
//测试对象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() ;
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) ;
Base::StoreObject(d,file1,len1) ;
((Data*)Base::LoadObject(file1,len1))->OutPut() ;
BUG2
如果先调用如下
Data *d=new Data(43);
Base::StoreObject(d,file1,len1) ;
然后把上述代码注释掉,在调用如下,在从文件加载 就会出现值的乱码
Base::StoreObject(d,file1,len1) ;
然后把上述代码注释掉,在调用如下,在从文件加载 就会出现值的乱码
((Data*)Base::LoadObject(file1,len1))->OutPut() ;
相反的 如果一次性把序列化和反序列化写在一起 ,那么即使下次调用多次也不会出问题,,,
算了考完试再继续Debug吧...哪位愿意帮忙调试下。。。