设为首页 加入收藏

TOP

5.3.3 序列化
2013-10-07 00:45:32 来源: 作者: 【 】 浏览:54
Tags:5.3.3 序列化

5.3.3  序列化

视频精讲:光盘\video\05\序列化.swf

序列化也需要得到CRuntimeClass结构的支持,它指的是从一个持久性存储介质中读出或者写入一个对象的过程。在MFC中,为了实现序列化,可以执行以下几步。

(1)令需要添加序列化支持的类继承于CObject类或其派生类。

(2)重载CObject类的Serialize()成员函数。

(3)在类的声明中添加DECLARE_SERIAL()宏。

(4)定义一个无参构造函数。

(5)在类的实现文件中添加IMPLEMENT_SERIAL()宏。

重载Serialize()的目的是让文档对象在执行打开/保存操作时,能够读取和存储复杂的类对象,其基本形式如下:

void CMFCDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
//在此处添加存储对象的代码
}
else
{
//在此处添加读取对象的代码
}
}
DECLARE_SERIAL()宏的作用是提供序列化的声明。在afx.h头文件下,宏DECLARE_ SERIAL ()的定义如下:
#define DECLARE_SERIAL(class_name) \
_DECLARE_DYNCREATE(class_name) \
AFX_API friend CArchive& AFXAPI operator>>
(CArchive& ar, class_name* &pOb);
而宏IMPLEMENT_SERIAL()的作用则是提供序列化的实现,其定义如下:
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
extern AFX_CLASSINIT _init_##class_name; \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
class_name::CreateObject, &_init_##class_name) \
AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
//实现重载的">>"操作符函数以读取对象
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
return ar; }

上述宏定义中,CArchive类是作为待序列化的对象与存储介质之间的一种媒介而存在的,该类的对象可以被看做是一个二进制流,用于实现对象的可序列化读写。使用CArchive对象时特别值得注意的是,对象的可序列化读写不能同时进行,即对于给定的CArchive对象在同一时间内只能执行单向地存储或读取操作。

在实现序列化的过程中,DECLARE_SERIAL()宏首先通过_DECLARE_DYNCREATE()宏为类定义了动态创建,然后,再以友元的形式重载操作符">>"。IMPLEMENT_SERIAL()宏给出了该重载函数的具体实现,它通过类的CreateObject()函数及">>"操作符调用CArchive对象的ReadObject()成员函数,以根据所获得的CRuntimeClass结构的内容从存储介质中读出对象。另外,用于保存对象的"<<"运算符的实现则是通过CArchive类的WriteObject()成员函数实现的,其代码如下:

AFXINLINE CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb)
{
ar.WriteObject(pOb);
return ar;
}
下面来看一下CArchive类的WriteObject()及ReadObject()成员函数的关键代码:
  WriteObject():
void CArchive::WriteObject(const CObject* pOb)
{
……//此处代码省略
if (pOb == NULL)
{
……//此处代码省略
}
else
if ((nObIndex = (DWORD)(DWORD_PTR)(*m_pStoreMap)[(void*)pOb]) != 0)
{
……//此处代码省略
}
else
{
//初始化对象的CRuntimeClass结构
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
//保存类信息
WriteClass(pClassRef);
……//此处代码省略
//调用对象的Serialize()成员函数实现序列化
((CObject*)pOb)->Serialize(*this);
}
}
}
ReadObject():
CObject* CArchive::ReadObject(const CRuntimeClass*
pClassRefRequested)
{
……//此处代码省略
UINT nSchema;
DWORD obTag;
//读取对象的CRuntimeClass结构信息
CRuntimeClass* pClassRef = ReadClass
(pClassRefRequested, &nSchema, &obTag);
CObject* pOb=NULL;
if (pClassRef == NULL)
{
……//此处代码省略
}
else
{
TRY
{
//动态创建对象
pOb = pClassRef->CreateObject();
   ……//此处代码省略
UINT nSchemaSave = m_nObjectSchema;
m_nObjectSchema = nSchema;
   //调用对象的Serialize()成员函数初始化对象的数据成员
pOb->Serialize(*this);
m_nObjectSchema = nSchemaSave;
ASSERT_VALID(pOb);
}
CATCH_ALL(e)
{
if(pOb!=NULL)
{
delete pOb;
pOb=NULL;
}
THROW_LAST();
}
END_CATCH_ALL
}
return pOb;
}

至此,我们可以看出,序列化存储对象的基本流程是:首先,写入初始化对象CRuntimeClass结构中的信息;然后,调用对象的Serialize()方法实现序列化。而序列化读取对象的基本流程则是:第一,获取对象的CRuntimeClass结构的信息;第二,根据所得的信息动态地创建对象;第三,调用对象的Serialize()方法初始化对象的数据成员。
【责任编辑:云霞 TEL:(010)68476606】

回书目   上一节   下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇5.1.1 模拟MFC机制 下一篇5.3.2 动态创建

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: