序列化:创建可序列化类

若要使类可序列化,需要执行五个主要步骤。 下面列出了它们,并在以下部分中进行了说明:

  1. 从 CObject 派生类 (或派生自 CObject某些类)。

  2. 重写 Serialize 成员函数

  3. 在类声明中使用 DECLARE_SERIAL 宏

  4. 定义不带参数的构造函数

  5. 在类的实现文件中使用 IMPLEMENT_SERIAL 宏

如果直接调用 CArchive 而不是通过 >><< CArchive 的运算符,Serialize则序列化不需要最后三个步骤。

从 CObject 派生类

基本序列化协议和功能在类中 CObject 定义。 通过将类派生自 CObject (或派生自 CObject的类)派生,如以下类 CPerson声明所示,你可以访问序列化协议和功能的 CObject访问。

重写序列化成员函数

Serialize 类中 CObject 定义的成员函数负责实际序列化捕获对象的当前状态所需的数据。 该 Serialize 函数具有 CArchive 用于读取和写入对象数据的参数。 CArchive 对象具有成员函数,IsStoring该函数指示是存储(写入数据)还是Serialize加载(读取数据)。 使用作为指南的结果IsStoring,可以使用插入运算符(<<)在对象中CArchive插入对象中的数据,或使用提取运算符(>>)提取数据。

请考虑派生自 CObject 且具有两个新的成员变量(类型 CStringWORD)的类。 以下类声明片段显示重写成员函数的新成员变量和声明 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);
};

重写序列化成员函数

  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::ReadCArchive::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宏的参数。 有关用法信息和示例,请参阅 GetObjectSchemaCArchive的成员函数。

以下示例演示如何对派生自CObject的类CPerson使用 IMPLEMENT_SERIAL:

IMPLEMENT_SERIAL(CPerson, CObject, 1)

拥有可序列化类后,可以序列化类的对象,如序列化 :序列化对象一文中所述。

另请参阅

序列化