使类可序列化需要五个主要步骤。下面列出了这些步骤并在以后章节内进行了解释:
从 CObject 派生类(或从 CObject 派生的某个类中派生)。 重写 Serialize 成员函数。 使用 DECLARE_SERIAL 宏(在类声明中)。 定义不带参数的构造函数。 为类在实现文件中使用 IMPLEMENT_SERIAL 宏。 如果直接调用 Serialize 而不是通过 CArchive 的“>>”和“<<”运算符调用,则序列化不需要最后三个步骤。
从 CObject 派生类
在 CObject 类中定义了基本的序列化协议和功能。正如在 CPerson 类的下列声明中所示,通过从 CObject 中(或从 CObject 的派生类中)派生类,可获得对 CObject 的序列化协议及功能的访问权限。
重写 Serialize 成员函数
在 CObject 类中定义的 Serialize 成员函数实际上负责对捕获对象的当前状态所必需的数据进行序列化。Serialize 函数具有 CArchive 参数,该函数使用其来读写对象数据。CArchive 对象具有成员函数 IsStoring,该成员函数指示 Serialize 正在存储(即正在写入数据)还是正在加载(即正在读取数据)。用 IsStoring 的结果作为参考,使用输出运算符 (<<) 将对象数据插入到 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.插入或提取您的类所特定的成员变量。
输出运算符及输入运算符与存档类交互作用以读写数据。下面的示例显示了如何实现以上声明的 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,防止程序读取对象的不正确版本。
如果要使 Serialize 成员函数能够读取多个版本(即,读取用应用程序的不同版本写入的文件),可将 VERSIONABLE_SCHEMA 值作为 IMPLEMENT_SERIAL 宏的参数。有关用法信息和示例,请参见 CArchive 类的 GetObjectSchema 成员函数。
以下示例显示了如何将 IMPLEMENT_SERIAL 用于从 CObject 派生的 CPerson 类。
IMPLEMENT_SERIAL( CPerson, CObject, 1 )
正如序列化:序列化对象文章中所讨论的,一旦具有可序列化的类,就可以序列化类的对象。