序列化储存.docx
《序列化储存.docx》由会员分享,可在线阅读,更多相关《序列化储存.docx(25页珍藏版)》请在冰豆网上搜索。
序列化储存
文档与序列化
一、文档的基本特征
文档类文件是从CDocument继承而来的。
TheCDocumentclassprovidesthebasicfunctionalityforuser-defineddocumentclasses.AdocumentrepresentstheunitofdatathattheusertypicallyopenswiththeFileOpencommandandsaveswiththeFileSavecommand.
翻译:
文档类提供用户自定义文档类的基本功能。
一个文档的打开命令和保存命令是数据单元特征。
CDocumentsupportsstandardoperationssuchascreatingadocument,loadingit,andsavingit.TheframeworkmanipulatesdocumentsusingtheinterfacedefinedbyCDocument.
翻译:
文档类支持标准操作有:
创建文档,载入文档,和保存。
框架界面使用由文档类定义的界面。
Anapplicationcansupportmorethanonetypeofdocument;forexample,anapplicationmightsupportbothspreadsheetsandtextdocuments.Eachtypeofdocumenthasanassociateddocumenttemplate;thedocumenttemplatespecifieswhatresources(forexample,menu,icon,oracceleratortable)areusedforthattypeofdocument.EachdocumentcontainsapointertoitsassociatedCDocTemplateobject.
翻译:
一个应用程序可以支持多于一种类型的文档;例如,一个应用程序可能同时支持电子表格和普通文本文档。
每一种类型的文档有一种关联文档模板;文档模板指定了(例如,菜单,图标,或者加速表格)使用这些类型的文档。
每个文档包含一个指针指向关联的模板对象。
UsersinteractwithadocumentthroughtheCViewobject(s)associatedwithit.Aviewrendersanimageofthedocumentinaframewindowandinterpretsuserinputasoperationsonthedocument.Adocumentcanhavemultipleviewsassociatedwithit.Whentheuseropensawindowonadocument,theframeworkcreatesaviewandattachesittothedocument.Thedocumenttemplatespecifieswhattypeofviewandframewindowareusedtodisplayeachtypeofdocument.
翻译:
用户将一个文档和一个视类对象想关联起来。
一个视类扮演一个嵌入在文档框架内的图像,在文档内解释用户的输入操作。
一个文档可以有多个视类与其关联。
当用户在一个文档上打开一个窗体,框架创造一个视图,把它放在文档上。
文档模板指定适合于用户文档类型的相同类的视图和框架窗口用来显示用户打开的文件。
Documentsarepartoftheframework'sstandardcommandroutingandconsequentlyreceivecommandsfromstandarduser-interfacecomponents(suchastheFileSavemenuitem).Adocumentreceivescommandsforwardedbytheactiveview.Ifthedocumentdoesn'thandleagivencommand,itforwardsthecommandtothedocumenttemplatethatmanagesit.
翻译:
文档是一个框架标准命令路由,因此从标准用户界面组件(如文件保存菜单项)接受命令。
一个文档由其活动视图迅速接受命令。
如果该文档没有没有响应给出的命令,那么该命令将交由文档模板来管理。
Whenadocument'sdataismodified,eachofitsviewsmustreflectthosemodifications.CDocumentprovidestheUpdateAllViewsmemberfunctionforyoutonotifytheviewsofsuchchanges,sotheviewscanrepaintthemselvesasnecessary.Theframeworkalsopromptstheusertosaveamodifiedfilebeforeclosingit.
翻译:
当一个文档数据发生改变,每一个它的视图将随即发生改变。
文档类提供更新所有视图成员函数来通报每一个视图的改变,因此视图可以在必要的时候被重绘。
框架也在关闭前迅速保存改动文件。
Toimplementdocumentsinatypicalapplication,youmustdothefollowing:
● DeriveaclassfromCDocumentforeachtypeofdocument.
● Addmembervariablestostoreeachdocument'sdata.
● Implementmemberfunctionsforreadingandmodifyingthedocument'sdata.Thedocument'sviewsarethemostimportantusersofthesememberfunctions.
● OverridetheCObject:
:
Serializememberfunctioninyourdocumentclasstowriteandreadthedocument'sdatatoandfromdisk.
翻译:
在一个典型类型的应用程序中实现一个文档,你必须按以下步骤:
● 为每一种类型的文档从CDocument派生一个类
● 增加成员函数来存储每一个文档的数据
● 为读写文档数据实现成员函数。
文档视图类是这个成员函数最重要的使用者。
● 在你的文档类重载CObject:
:
Serialize成员函数,来将文档数据从磁盘读写。
序列化:
本文解释Microsoft基础类库(MFC)中提供的序列化机制,该机制使对象可以在程序运行之间保持。
序列化是指将对象写入永久性存储媒体(如磁盘文件)或从其中读取对象的进程。
MFC对CObject类中的序列化提供内置支持。
因此,所有从CObject派生的类都可利用CObject的序列化协议。
序列化的基本思想是对象应能将其当前状态(通常由该对象的成员变量指示)写入永久性存储中。
以后,通过从存储中读取对象状态或反序列化对象状态,可以重新创建该对象。
序列化处理序列化对象时使用的对象指针和对象循环引用的所有详细资料。
关键之处在于对象本身负责读写其自身状态。
因此,对于可序列化的类,必须实现基本的序列化操作。
正如“序列化”文章组中所显示的那样,很容易将该功能添加到类中。
MFC将CArchive类的对象用作将被序列化的对象和存储媒体之间的中介物。
该对象始终与CFile对象相关联,它从CFile对象获得序列化所需的信息,包括文件名和请求的操作是读取还是写入。
执行序列化操作的对象可在不考虑存储媒体本质的情况下使用CArchive对象。
CArchive对象使用重载输出运算符(<<)和输入运算符(>>)来执行读写操作。
有关更多信息,请参见“序列化:
序列化对象”文章中的通过存档存储和加载CObjects。
注意 请不要将CArchive类与通用iostream类混淆,iostream类只用于格式化的文本。
而CArchive类则用于二进制格式的序列化对象。
如果愿意,可以不使用MFC序列化而为永久性数据存储创建自己的机制。
您将需要在用户的命令处重写启动序列化的类成员函数。
请参见ID_FILE_OPEN、ID_FILE_SAVE及ID_FILE_SAVE_AS标准命令的技术说明22中的讨论。
下列文章介绍了序列化所需的两个主要任务:
● 序列化:
创建可序列化的类
● 序列化:
序列化对象
序列化:
序列化与数据库输入/输出的对比一文描述了序列化在数据库应用程序中何时是适当的输入/输出技术。
通过存档存储和加载CObjects
通过存档存储及加载CObject需要额外注意。
在某些情况下,应调用对象的Serialize函数,其中,CArchive对象是Serialize调用的参数,与使用CArchive的“<<”或“>>”运算符不同。
要牢记的重要事实是:
CArchive的“>>”运算符基于由存档先前写到文件的CRuntimeClass信息构造内存中的CObject。
因此,是使用CArchive的“<<”和“>>”运算符还是调用Serialize,取决于是否需要加载存档基于先前存储的CRuntimeClass信息动态地重新构造对象。
在下列情况下使用Serialize函数:
● 反序列化对象时,预先知道对象的确切的类。
● 反序列化对象时,已为其分配了内存。
警告 如果使用Serialize函数加载对象,也必须使用Serialize函数存储对象。
不要使用CArchive的“<<”运算符先存储,然后使用Serialize函数进行加载;或使用Serialize函数存储,然后使用CArchive的“>>”运算符进行加载。
以下示例阐释了这些情况:
classCMyObject:
publicCObject
{
//...Memberfunctions
public:
CMyObject(){}
virtualvoidSerialize(CArchive&ar){}
//Implementation
protected:
DECLARE_SERIAL(CMyObject)
};
classCOtherObject:
publicCObject
{
//...Memberfunctions
public:
COtherObject(){}
virtualvoidSerialize(CArchive&ar){}
//Implementation
protected:
DECLARE_SERIAL(COtherObject)
};
classCCompoundObject:
publicCObject
{
//...Memberfunctions
public:
CCompoundObject();
virtualvoidSerialize(CArchive&ar);
//Implementation
protected:
CMyObjectm_myob;//Embeddedobject
COtherObject*m_pOther;//Objectallocatedinconstructor
CObject*m_pObDyn;//Dynamicallyallocatedobject
//..Othermemberdataandimplementation
DECLARE_SERIAL(CCompoundObject)
};
IMPLEMENT_SERIAL(CMyObject,CObject,1)
IMPLEMENT_SERIAL(COtherObject,CObject,1)
IMPLEMENT_SERIAL(CCompoundObject,CObject,1)
CCompoundObject:
:
CCompoundObject()
{
m_pOther=newCOtherObject;//Exacttypeknownandobjectalready
//allocated.
m_pObDyn=NULL;//Willbeallocatedinanothermemberfunction
//ifneeded,couldbeaderivedclassobject.
}
voidCCompoundObject:
:
Serialize(CArchive&ar)
{
CObject:
:
Serialize(ar);//AlwayscallbaseclassSerialize.
m_myob.Serialize(ar);//CallSerializeonembeddedmember.
m_pOther->Serialize(ar);//CallSerializeonobjectsofknownexacttype.
//Serializedynamicmembersandotherrawdata
if(ar.IsStoring())
{
ar<//Storeothermembers
}
else
{
ar>>m_pObDyn;//Polymorphicreconstructionofpersistent
//object
//loadothermembers
}
}
总之,如果可序列化的类将嵌入的CObject定义为成员,则不应使用该对象的CArchive的“<<”和“>>”运算符,而应调用Serialize函数。
同时,如果可序列化的类将指向CObject(或从CObject派生的对象)的指针定义为成员,但在自己的构造函数中将其构造为其他对象,则也应调用Serialize。
序列化:
创建可序列化的类
ms-help:
//MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/vccore/html/_core_serialization.3a_.making_a_serializable_class.htm
使类可序列化需要五个主要步骤。
下面列出了这些步骤并在以后章节内进行了解释:
1.从CObject派生类(或从CObject派生的某个类中派生)。
2.重写Serialize成员函数。
3.使用DECLARE_SERIAL宏(在类声明中)。
4.定义不带参数的构造函数。
5.为类在实现文件中使用IMPLEMENT_SERIAL宏。
如果直接调用Serialize而不是通过CArchive的“>>”和“<<”运算符调用,则序列化不需要最后三个步骤。
从CObject派生类
在CObject类中定义了基本的序列化协议和功能。
正如在CPerson类的下列声明中所示,通过从CObject中(或从CObject的派生类中)派生类,可获得对CObject的序列化协议及功能的访问权限。
重写Serialize成员函数
在CObject类中定义的Serialize成员函数实际上负责对捕获对象的当前状态所必需的数据进行序列化。
Serialize函数具有CArchive参数,该函数使用其来读写对象数据。
CArchive对象具有成员函数IsStoring,该成员函数指示Serialize正在存储(即正在写入数据)还是正在加载(即正在读取数据)。
用IsStoring的结果作为参考,使用输出运算符(<<)将对象数据插入到CArchive对象中或使用输入运算符(>>)提取数据。
假定一个类是从CObject派生的并具有两个新成员变量,分别为CString和WORD类型。
下列类声明段显示了新成员变量和重写的Serialize成员函数的声明:
classCPerson:
publicCObject
{
public:
DECLARE_SERIAL(CPerson)
//emptyconstructorisnecessary
CPerson(){};
CStringm_name;
WORDm_number;
voidSerialize(CArchive&archive);
//restofclassdeclaration
};
重写Serialize成员函数
1.调用Serialize的基类版本以确保序列化对象的继承部分。
2.插入或提取您的类所特定的成员变量。
输出运算符及输入运算符与存档类交互作用以读写数据。
下面的示例显示了如何实现以上声明的CPerson类的Serialize:
void
CPerson:
:
Serialize( CArchive
&
archive )
{
//
call base class function first
//
base class is CObject in this case
CObject:
:
Serialize( archive );
//
now do the stuff for our specific class
if
( archive.IsStoring() )
archive
<<
m_name
<<
m_number;
else
archive
>>
m_name
>>
m_number;
}
也可使用CArchive:
:
Read及CArchive:
:
Write成员函数来读写大量未键入的数据。
使用DECLARE_SERIAL宏
在支持序列化的类的声明中需要DECLARE_SERIAL宏,如下所示:
class
CPerson :
public
CObject
{
DECLARE_SERIAL( CPerson )
//
rest of declaration follows
}
;
定义不带参数的构造函数
反序列化对象(从磁盘上加载)后,MFC重新创建这些对象时,需要一个默认的构造函数。
反序列化进程将用重新创建对象所需的值填充所有成员变量。
可将该构造函数声明为公共的、受保护的或私有的。
如果使该构造函数成为受保护的或私有的,请确保它将仅由序列化函数使用。
该构造函数必须使对象处于这样一种状态:
必要时,可允许将其安全删除。
注意 如果忘记在使用DECLARE_SERIAL及IMPLEMENT_SERIAL宏的类中定义不带参数的构造函数,将在使用IMPLEMENT_SERIAL宏的行上得到“没有可用的默认构造函数”编译器警告。
在实现文件中使用IMPLEMENT_SERIAL宏
IMPLEMENT_SERIAL宏用于定义从CObject中派生可序列化类时所需的各种函数。
在类的实现文件(.CPP)中使用这个宏。
该宏的前两个参数是类名和直接基类的名称。
该宏的第三个参数是架构编号。
架构编号实质上是类对象的版本号。
架构编号使用大于或等于零的整数。
(请不要将该架构编号与数据库术语混淆。
)
MFC序列化代码在将对象读取到内存时检查该架构编号。
如果磁盘上对象的架构编号与内存中类的架构编号不匹配,库将引发CArchiveException,防止程序读取对象的不正确版本。
如果要使Seri