分享

孙鑫VC视频教程笔记之第十三课“文档与串行化”

 Alex@ZW 2010-11-04

What is the serialization?

The CArchive class allows you to save a complex network of objects in a permanent binary form (usually disk storage) that persists after those objects are deleted. Later you can load the objects from persistent storage, reconstituting them in memory. This process of making data persistent is called “serialization.”

“Serialization” is the process of writing or reading an object to or from a persistent storage medium, such as a disk file. MFC supplies built-in support for serialization in the class CObject. Thus, all classes derived from CObject can take advantage of CObject’s serialization protocol.

You can think of an archive object as a kind of binary stream. Like an input/output stream, an archive is associated with a file and permits the buffered writing and reading of data to and from storage. An input/output stream processes sequences of ASCII characters, but an archive processes binary object data in an efficient, nonredundant format.

You must create a CFile object before you can create a CArchive object. In addition, you must ensure that the archive’s load/store status is compatible with the file’s open mode. You are limited to one active archive per file.

 

创建CArchive之前必须创一个CFile,必须保证CArchiveload/store状态和文件的打开模式相一致。一个文件只能有一个活动的CArchive

当你创建一个CArchive对象时,和CFile或者其派生类关联来表示一个打开的文件。也可以指定CArchive是否是用来loadstoreArchive不仅可以处理基本类型,也可以处理CObject派生的对象

 

1、基本数据类型的串行化:

写入

 CFile file("1.txt",CFile::modeCreate | CFile::modeWrite);

 CArchive ar(&file,CArchive::store);

 int i=4;

 float b=1.3f;   //C默认用float定义而不加f的为double

 CString str="SongPeng";

 ar<<i<<b<<str;

读取

 CFile file("1.txt",CFile::modeRead);

 CArchive ar(&file,CArchive::load);

 int i;

 float b;

 CString str;

 CString strRestult;

 ar>>i>>b>>str;

 strRestult.Format("%d %f %s",i,b,str);

 MessageBox(strRestult);

 

2、自定义对象的串行化:

1、  创建一个具有串行化的功能的类分四步骤:具体代码实现的例子详见自己编写的“MySample”

a.      Deriving Your Class from CObject

b.      Overriding the Serialize Member Function

Ø         Call your base class version of Serialize to make sure that the inherited portion of the object is serialized.

Ø         Insert or extract the member variables specific to your class

Sample:

头文件声明:

class CPerson : public CObject

{

public:

    DECLARE_SERIAL( CPerson ) //必须的

    CPerson(){}; // empty constructor is necessary

 

    CString m_name;

    WORD   m_number;

 

    void Serialize( CArchive& archive );

};

Cpp文件实现:

IMPLEMENT_SERIAL( CPerson, CObject, 1 ) //DECLARE_SERIAL对应

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;

}

 

c.      Using the DECLARE_SERIAL Macro

The DECLARE_SERIAL macro is required in the declaration of classes that will support serialization, as shown here:

class CPerson : public CObject

{

    DECLARE_SERIAL( CPerson )

    // rest of declaration follows...

};

 

d.      Defining a Constructor with No Arguments: default constructor

e.      Using the IMPLEMENT_SERIAL Macro in the Implementation File

IMPLEMENT_SERIAL( CPerson, CObject, 1 ) //放在类的cpp文件中,上面已写

2、  将对象串行化的动作一般在CDocument类中的Serialize函数中实现,即保存与加载。

3、  单文档程序的保存与打开文件按钮和菜单命令,会调用CDocument类中的Serialize函数,从而达到内容的保存与加载

4、  IMPLEMENT_SERIAL宏的第一个参数是自身类的类名,第二个参数是它继承的类,不一定是CObject,第三个参数是定义保存文件的版本号

5、  框架内部的调用过程:

CDocument类中的OnNewDocument函数在程序创建和点击新建菜单时调用,在其中可以调用SetTitle函数修改程序文档标题,另一个可以修改程序标题的地方是资源中的String Table找到IDM_MAINFRAME,它也是Menu的资源名称,IDM_MAINFRAME对应的字符串是以\n为分隔符,在第二个\n前添加文档标题内容。在CApp这个类中InitInstance函数中有以下代码:

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

      IDR_MAINFRAME,

      RUNTIME_CLASS(CMySampleDoc),

      RUNTIME_CLASS(CMainFrame),       // main SDI frame window

      RUNTIME_CLASS(CMySampleView));

这段代码中将字符串资源,框架类,文档类,视图类组合到一起,成为一体

关于String TableIDM_MAINFRAME字符串中各子字符串的含义:

(1)CDocTemplate::windowTitle,主窗口标题栏上的字符串,MDI程序不需要指定,将以IDR_MAINFRAME字符串为默认值。

(2)CDocTemplate::docName,缺省文档的名称。如果没有指定,缺省文档的名称是无标题。

(3)CDocTemplate::fileNewName,文档类型的名称。如果应用程序支持多种类型的文档,此字符串将显示在"File/New"对话框中。如果没有指定,就不能够在"File/New"对话框处理这种文件。

(4)CDocTemplate::filterName,文档类型的描述和一个适用于此类型的通配符过滤器。这个字符串将出现在“File/Open”对话框中的文件类型列表框中。要和CDocTemplate::filterExt一起使用。

(5)CDocTemplate::filterExt,文档的扩展名。如果没有指定,就不能够在“File/Open”对话框中处理这种文档。要和CDocTemplate::filterName一起使用。

(6)CDocTemplate::regFileTypeId,如果你以::RegisterShellFileTypes向系统的注册表注册文件类型,此值会出现在HEY_CLASSES_ROOT之下成为其子项,并仅供Windows内部使用。如果没有指定,这种文件类型就无法注册。

(7)CDocTemplate::regFileTypeName,这也是存储在注册表中的文件类型名称。它会显示于程序中用以访问注册表的对话框内。

6、  关于Serialize函数的调用顺序是,首先框架类的该函数被调用,然后是自定义类中的该函数被调用

7、  在文档类中获得视图类的对象
a.
调用CDocument::GetFirstViewPosition()

b.调用CDocument::GetNextView() 得到

如果是多文档程序:

POSITION pos=GetFirstViewPosition();

while (pos!=NULL) //ps是一个迭代器

{

      CView* pFirstView = GetNextView( pos );

      ……….

}

如果是单文档程序:

POSITION pos=GetFirstViewPosition();

CView* pFirstView = GetNextView( pos );

8、  MSDN中关于OnNewDocument的解释有如下一段话:

Called by the framework as part of the File New command. The default implementation of this function calls the DeleteContents member function to ensure that the document is empty and then marks the new document as clean.

所以如果在单文档程序中如果在现有文档上打开一个新文档是,系统会自动销毁前一个文档,所以在前一个文档中所创建的堆对象应该及时删除,删除这些地方最好的地方就是在DeleteContents函数中,否则必须等到程序退出的时候,才会将堆对象进行自动销毁。

9、  MFC给我们提供Document/View结构,将一个应用程序所需要的数据处理与显示的函数空壳都设计好了,这些函数都是虚函数,我们可以在派生类中重写这些函数。有关文件读写的操作在CDocumentSerialize函数中进行,有关数据和图形显示的操作在CViewOnDraw函数中进行。我们在其派生类中,只需要去关注SerializeOnDraw函数就可以了,其它的细节我们不需要去理会,程序就可以良好地运行。

10、              当我们按下“File/Open”Application Framework会激活文件打开对话框,让你指定文件名,然后自动调用CGraphicDoc::Serialize读取文件。Application Framework还会调用CGraphicView::OnDraw,传递一个显示DC,让你重新绘制窗口内容。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多