Сериализация. Создание сериализуемого класса

Для сериализации класса необходимо выполнить пять основных шагов. Они перечислены ниже и описаны в следующих разделах:

  1. Производный класс от CObject (или из определенного класса, производный от CObject).

  2. Переопределение функции-члена Serialize.

  3. Использование макроса DECLARE_SERIAL в объявлении класса.

  4. Определение конструктора, который не принимает аргументов.

  5. Использование макроса IMPLEMENT_SERIAL в файле реализации для класса.

Если вы вызываете Serialize напрямую, а не через >><< операторы CArchive, последние три шага не требуются для сериализации.

Извлечение класса из CObject

Базовый протокол сериализации и функциональные возможности определяются в CObject классе. При производных от класса (или из класса, производных CObjectот CObject ), как показано в следующем объявлении классаCPerson, вы получаете доступ к протоколу сериализации и функциональным CObjectвозможностям.

Переопределение функции-члена сериализации

Функция-член 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

  1. Вызовите версию Serialize базового класса, чтобы убедиться, что наследуемая часть объекта сериализуется.

  2. Вставьте или извлеките переменные-члены, относящиеся к классу.

    Операторы вставки и извлечения взаимодействуют с архивным классом для чтения и записи данных. В следующем примере показано, как реализовать 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 требуется конструктор по умолчанию при повторном создании объектов по мере их десериализации (загружается с диска). Процесс десериализации заполняет все переменные-члены значениями, необходимыми для повторного создания объекта.

Этот конструктор может быть объявлен общедоступным, защищенным или закрытым. Если вы делаете его защищенным или закрытым, убедитесь, что он будет использоваться только функциями сериализации. Конструктор должен поместить объект в состояние, позволяющее удалить его при необходимости.

Примечание.

Если вы забыли определить конструктор без аргументов в классе, использующего макросы DECLARE_SERIAL и IMPLEMENT_SERIAL, вы получите предупреждение компилятора "нет конструктора по умолчанию" в строке, где используется макрос IMPLEMENT_SERIAL.

Использование макроса IMPLEMENT_SERIAL в файле реализации

Макрос IMPLEMENT_SERIAL используется для определения различных функций, необходимых при наследовав из сериализуемого класса CObject. Этот макрос используется в файле реализации (. CPP) для класса. Первые два аргумента макроса — это имя класса и имя его немедленного базового класса.

Третий аргумент этого макроса — это номер схемы. Номер схемы по сути является номером версии для объектов класса. Используйте целое число больше или равно 0 для номера схемы. (Не путайте этот номер схемы с терминологией базы данных.)

Код сериализации MFC проверка номер схемы при чтении объектов в память. Если номер схемы объекта на диске не соответствует номеру схемы класса в памяти, библиотека вызовет CArchiveExceptionисключение, предотвращающее чтение неправильной версии объекта в программе.

Если вы хотите, чтобы функция-член Serialize могла читать несколько версий , то есть файлы, написанные с разными версиями приложения, можно использовать значение VERSIONABLE_SCHEMA в качестве аргумента макроса IMPLEMENT_SERIAL. Сведения об использовании и пример см. в GetObjectSchema функции-члене класса CArchive.

В следующем примере показано, как использовать IMPLEMENT_SERIAL для класса, CPersonкоторый является производным от CObject:

IMPLEMENT_SERIAL(CPerson, CObject, 1)

После создания сериализуемого класса можно сериализовать объекты класса, как описано в статье Сериализация: сериализация объекта.

См. также

Сериализация