序列化:定义可序列化的类
使类可序列化所需的五个主要步骤。 下面列出了这些步骤,后续章节中对它们进行了说明:
从 CObject 派生类(或者从派生自
CObject
的某个类进行派生)。在类声明中的使用 DECLARE_SERIAL 宏。
如果直接调用 Serialize
而不是通过 CArchive 的 >> 和 << 运算符进行调用,则最后三个步骤对序列化来说不是必需的。
从 CObject 派生你的类
基本序列化协议和功能在 CObject
类中定义。 通过从 CObject
或派生自 CObject
的类派生您的类(如类 CPerson
的以下声明中所示),您将能够访问 CObject
的序列化协议和功能。
替代 Serialize 成员函数
在 Serialize
类中定义的 CObject
成员函数负责实际上序列化捕获对象的当前状态所需的数据。 Serialize
函数具有一个 CArchive
参数,供它读取和写入对象数据。 CArchive 对象具有成员函数 IsStoring
,该函数指示 Serialize
是进行存储(写入数据)还是加载(读取数据)。 以 IsStoring
的结果为参考,可使用插入运算符 (<<) 将对象的数据插入 CArchive
对象或使用提取运算符 (>>) 提取数据。
请考虑使用派生自 CObject
并包含两个类型分别为 CString
和 WORD 的新成员变量的类。 以下类声明片段显示了新成员变量以及重写的 Serialize
成员函数的声明:
class CPerson : public CObject
{
public:
DECLARE_SERIAL(CPerson)
// empty constructor is necessary
CPerson();
virtual ~CPerson();
CString m_name;
WORD m_number;
void Serialize(CArchive& archive);
};
重写 Serialize 成员函数
调用基类版本的
Serialize
以确保对象的继承部分已序列化。插入或提取特定于您的类的成员变量。
插入和提取运算符与存档类交互以读取和写入数据。 以下代码示例演示如何为前面声明的
Serialize
类实现CPerson
: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
{
public:
DECLARE_SERIAL(CPerson)
定义没有参数的构造函数
当 MFC 因为对象被反序列化(从磁盘加载)而重新创建对象时,MFC 需要一个默认构造函数。 反序列化过程将使用重新创建对象所需的值填写所有成员变量。
此构造函数可声明为公共、受保护或私有。 如果您使它成为受保护或私有构造函数,您就帮助确保了它只会由序列化函数使用。 构造函数必须将对象设为允许它在必要时删除的状态。
注意
如果忘记在使用 DECLARE_SERIAL 和 IMPLEMENT_SERIAL 宏的类中定义没有参数的构造函数,你将在使用 IMPLEMENT_SERIAL 宏的行上获得“没有默认构造函数可用”编译器警告。
在实现文件中使用 IMPLEMENT_SERIAL 宏
IMPLEMENT_SERIAL 宏用于定义从 CObject
派生可序列化类时所需的各种功能。 您为您的类在实现文件 (.cpp) 中使用此宏。 此宏的前两个参数是类的名称和其直接基类的名称。
该宏的第三个参数是一个架构数字。 架构数字本质上是类的对象的版本号。 请对架构数字使用大于或等于 0 的整数值。 (不要将此架构数字与数据库术语混淆。)
MFC 序列化代码在将对象读入内存时检查架构数字。 如果磁盘上的对象的架构数字与内存中的架构数字不匹配,库将引发 CArchiveException
,这会阻止您的程序读取不正确的版本的对象。
如果希望 Serialize
成员函数能够读取多个版本(即,用不同版本的应用程序编写的文件),可使用值 VERSIONABLE_SCHEMA 作为 IMPLEMENT_SERIAL 宏的自变量。 有关用法信息和示例,请参阅类 GetObjectSchema
的 CArchive
成员函数。
以下示例演示如何为派生自 CObject
的类 CPerson
使用 IMPLEMENT_SERIAL:
IMPLEMENT_SERIAL(CPerson, CObject, 1)
获得可序列化的类后,可序列化该类的对象,如序列化:序列化对象一文所述。