Serialization:Making a serializable Class

来源:互联网 发布:可以刷ubuntu的平板 编辑:程序博客网 时间:2024/06/03 14:00
串行化:定制一个可串行化的类

要使一个类可以被串行化,需要以下5个步骤:

1.将你的类从CObjcet类派生(或是从CObjcet类的子类派生)。
2.重写成员函数Serialize。
3.在类的声明中添加DECLARE_SERIAL宏。
4.定义一个没有参数的构造函数。
5.在类的实现文件中添加IMPLEMENT_SERIAL宏。

如果你不使用CArchive类的>>和<<运算符,而是直接调用类的Serialize函数,最后3个步骤就不需要了。


使你的类从CObject类派生


串行化的基本协议和功能都在CObjcet类中定义了。通过将你的子类从CObject类(或是COjcet类的子类)派生,如下面CPerson类的声明所显示的一样,你就可以使用Object类的串行化的协议和功能了。

重写Serialize成员函数


Serialize成员函数,定义在CObject类中,负责对用来获取对象当前状态的必要数据进行串行化。Serialize函数带有一个CArchive参数,用来读取和写入对象的数据。CArchive的对象的成员函数IsStoring指示了Serialize函数是存储(写入数据)还是读取(读取数据)。把IsStoring的返回值作为向导,你可以用<<运算符将你的数据插入到CArchive的对象中,或用>>运算符将数据从CArchive的对象中提取出来。


一个从CObject类派生的类有两个分别是CString和WORD类型的新成员变量。下面的类的声明片段展示了新的成员变量和重写Serialize成员函数的声明:

class CPerson : public CObject
{
public:
    DECLARE_SERIAL( CPerson )
    // empty constructor is necessary  需要一个不带参数的构造函数
    CPerson(){};

    CString m_name;
    WORD   m_number;

    void Serialize( CArchive& archive );
    
    // rest of class declaration
};

重写Serialize成员函数

1.调用基类的Serialize以确认对象继承来的部分已被串行化。
2.加入或提取你的类特有的成员变量。
插入(“<<”)和提取(“>>”)运算符和archive类相互配合读取和写入数据。
下面的例子展示了如何为上面声明的类实现Serialize函数:

void CPerson::Serialize( CArchive& archive )
{
    // call base class function first     //   首先调用基类的Serialize函数
    // base class is CObject in this case   //   这个例子中基类是CObject
    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在重新构造你的对象的时候需要一个默认的构造函数。解串行化的过程会给所有成员变量赋值,从而重新构造对象。

这个构造函数可以被声明为公有(public)、保护(protected)、私有(private)类型。如果你将它设为保护或私有类型,你得保证它只能被用来串行化的函数使用。这个构造函数必须使对象在必要的时候允许被安全删除。

注意:在包含DECLARE_SERIAL和IMPLEMENT_SERIAL宏的类中,如果你忘了定义不带参数的构造函数,你会在IMPLEMENT_SERIAL宏处看到“no default constructor available”的编译警告。


在实现文件中使用IMPLEMENT_SERIAL宏


当你从CObject继承一个可串行化的类的时候,IMPLEMENT_SERIAL宏被用来定义各种需要的函数。你应该在你的实现文件(.CPP文件)中使用这个宏。这个宏的第一和第二个参数是你的类的名称和基类(最近的基类)的名称。

宏的第三个参数是个计划号码(schema number).这计划号码本质上是一个类的对象的版本号。计划号码是一个大于或等于0的整数。(不要把这个计划号码和数据库的专用术语混淆起来)

MFC串行化代码会在将对象数据读入内存的时候核对这个版本号。如果从磁盘上读入的对象的版本号和内存里类的版本号不一样,MFC库会产生一个CArchiveException来阻止你的程序读取版本不正确的对象。

如果你希望你的Serialize函数能够读取含有多个版本的对象的文件——也就是由不同版本的应用程序写成的文件——你可以将VERSIONABLE_SCHEMA这个值作为IMPLEMENT_SERIAL宏的参数。要获取使用方法和例子,请查看CArchive的成员函数GetObjectSchema。

下面的例子展示了如何为CPerson类(从CObject派生的类)添加IMPLEMENT_SERIAL宏:
IMPLEMENT_SERIAL( CPerson, CObject, 1 )

一旦你有了一个可串行化的类,你就可以对这个类的对象进行串行化了,就像“Serialization:Serializing an Object”这篇文章中讨论的一样。
原创粉丝点击