Сериализация. Создание сериализуемого класса
Для сериализации класса необходимо выполнить пять основных шагов. Они перечислены ниже и описаны в следующих разделах:
Производный класс от CObject (или из определенного класса, производный от
CObject
).Переопределение функции-члена Serialize.
Использование макроса DECLARE_SERIAL в объявлении класса.
Использование макроса 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
Вызовите версию
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 требуется конструктор по умолчанию при повторном создании объектов по мере их десериализации (загружается с диска). Процесс десериализации заполняет все переменные-члены значениями, необходимыми для повторного создания объекта.
Этот конструктор может быть объявлен общедоступным, защищенным или закрытым. Если вы делаете его защищенным или закрытым, убедитесь, что он будет использоваться только функциями сериализации. Конструктор должен поместить объект в состояние, позволяющее удалить его при необходимости.
Примечание.
Если вы забыли определить конструктор без аргументов в классе, использующего макросы 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)
После создания сериализуемого класса можно сериализовать объекты класса, как описано в статье Сериализация: сериализация объекта.