TN002: Постоянный формат данных объекта

Это примечание описание процедур MFC, которые поддерживают постоянные объекты C++ и формат данных объекта при сохранении в файл.Это относится только к классам с DECLARE_SERIAL и IMPLEMENT_SERIAL макросов.

Проблема

Реализация MFC для постоянных данных сохраняет данные для многих объектов в смежных часть файла.Объект Serialize метод преобразует данные объекта в двоичном формате compact.

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

Эта заметка описывается реализация CArchive элементы CArchive::ReadObject и CArchive::WriteObject.Вы увидите код для этих функций в Arcobj.cpp и реализацию основных CArchive в Arccore.cpp.Код пользователя не вызывает ReadObject и WriteObject напрямую.Вместо этого использовать эти объекты данного класса строго типизированным и извлечение операторами, которые создаются автоматически DECLARE_SERIAL и IMPLEMENT_SERIAL макросов.В следующем коде показано, как WriteObject и ReadObject неявно вызывается:

class CMyObject : public CObject
{
    DECLARE_SERIAL(CMyObject)
};

IMPLEMENT_SERIAL(CMyObj, CObject, 1)

// example usage (ar is a CArchive&)
CMyObject* pObj;
CArchive& ar;
ar << pObj;        // calls ar.WriteObject(pObj)
ar >> pObj;        // calls ar.ReadObject(RUNTIME_CLASS(CObj))

Сохранение объектов в хранилище (CArchive::WriteObject)

Метод CArchive::WriteObject записывает данные заголовка, который используется для восстановления объекта.Эти данные состоит из двух частей: тип и состояние объекта.Этот метод также отвечает за поддержание удостоверения объекта записывается, таким образом, сохраняется только одна копия независимо от числа указателей на объект (включая циклические ссылки).

Сохранение (Вставка) и восстановление объектов (извлечение) зависит от нескольких «манифеста константы.» Ниже приведены значения, которые хранятся в двоичном формате и содержат важные сведения в архив (Обратите внимание, что префикс «w» указывает количества 16 бит):

Tag

Описание

wNullTag

Для указателей на объект NULL (0).

wNewClassTag

Указывает, что класс описания ниже новый контекст этого архива (-1).

wOldClassTag

Указывает, что класс объекта чтения наблюдалась в данном контексте (0x8000).

При сохранении объектов архива поддерживает CMapPtrToPtr ( m_pStoreMap) это сопоставление хранимых объект 32-разрядного постоянный идентификатор (PID).PID назначается для каждого уникального объекта и каждое уникальное имя класса, сохраняется в контексте архива.Эти чертежи раздаются последовательно, начиная с 1.Эти PID не имеют вне области архива и в частности, которые не следует путать с номера записей или других идентификаторов элементов.

В CArchive класс, PID 32-разрядный, но они записываются как 16-разрядные если они не больше, чем 0x7FFE.Большой PID записываются как 0x7FFF следуют 32-разрядный код продукта.Это обеспечивает совместимость с проектов, созданных в более ранних версиях.

При запросе для сохранения объекта в архив (обычно с помощью оператора глобального курсора) проверяется значение NULL, от CObject указателя.Если указатель равен NULL, wNullTag вставляется потока архива.

Если указатель мыши не равно NULL и может быть сериализован (класс DECLARE_SERIAL класса), код проверяет m_pStoreMap для просмотра ли объект уже сохранен.Если он имеет код вставляет 32-разрядных PID, связанные с этим объектом в поток архива.

Если объект не сохранялся, существуют две возможности рассмотреть: объект и точный тип объекта (то есть класс) новый контекст этого архива или объект имеет точный тип уже видели.Чтобы определить ли тип наблюдалась, запросы код m_pStoreMap для CRuntimeClass объект, который соответствует CRuntimeClass объекта, связанного с сохраняемого объекта.При соответствии, WriteObject вставляет тег, который является побитовое OR из wOldClassTag и этот индекс.Если CRuntimeClass нового контекста этого архива, WriteObject присваивается новый номер продукта класса и вставляет его в архив, предшествует wNewClassTag значение.

Дескриптор для данного класса помещается в архив с помощью CRuntimeClass::Store метод.CRuntimeClass::StoreВставляет номер схемы классов (см. ниже) и текст ASCII имя класса.Обратите внимание, что использование имени текста ASCII не гарантирует уникальность архив приложениями.Таким образом следует пометить файлы данных для предотвращения повреждения.После ввода сведений о классе, архив помещает объект в m_pStoreMap , а затем вызывает Serialize метода для вставки данных класса.Помещение объектов в m_pStoreMap перед вызовом метода Serialize предотвращает сохранение в хранилище несколько копий объекта.

При возвращении исходного вызова (обычно корень сети объектов), необходимо вызвать CArchive::Close.Если планируется выполнять другие CFileопераций, необходимо вызвать CArchive метод очистки для предотвращения повреждения архива.

ПримечаниеПримечание

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

Загрузка объектов из хранилища (CArchive::ReadObject)

Загрузка (извлечение) объектов использует CArchive::ReadObject метод и обратный WriteObject.Как и в WriteObject, ReadObject не вызывается непосредственно кодом пользователя; пользовательский код должен вызывать оператор извлечения строго типизированным, который вызывает ReadObject ожидаемый CRuntimeClass.Это гарантирует целостность тип операции извлечения.

Поскольку WriteObject реализации назначенных увеличение PID, начиная с 1 (как пустой объект предварительно 0), ReadObject реализации массив можно использовать для отслеживания состояния контекста архив.При чтении PID из хранилища, если код продукта больше, чем текущий верхнюю границу m_pLoadArray, ReadObject знает, что соответствует нового объекта (или описание класса).

Схема номеров

Схема номер, который присваивается класс при IMPLEMENT_SERIAL обнаружен метод класса, «версия» реализацию класса.Схема ссылается на реализацию класса, не на количество данного объекта была сделана постоянных (обычно называют версия объекта).

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

CArchive::ReadObject Вызовет метод CArchiveException при обнаружении номер схемы в постоянном хранилище, отличается от схемы описания класса в памяти.Не просто восстановить из этого исключения.

Можно использовать VERSIONABLE_SCHEMA в сочетании с (побитовое OR) вашей версии схемы, чтобы сохранить это исключение возникает.С помощью VERSIONABLE_SCHEMA, код может выполнить соответствующее действие его Serialize функции, проверив возвращаемое значение из CArchive::GetObjectSchema.

Непосредственно сериализации вызова

Во многих случаях издержки схема архива общего объекта WriteObject и ReadObject не является обязательным.Это распространенный случай сериализации данных в CDocument.В этом случае Serialize метод CDocument вызывается непосредственно, без извлечения или вставки операторов.Содержимое документа, в свою очередь может использовать более общую схему архив объекта.

Вызов Serialize непосредственно имеет следующие преимущества и недостатки:

  • Нет лишних байтов добавляются в архиве до или после сериализации объекта.Это не только делает сохраненных данных меньшего размера, но позволяет реализовать Serialize подпрограмм, которые могут обрабатывать любые форматы файлов.

  • MFC настраивается таким образом, WriteObject и ReadObject реализации и связанной коллекции не будет связан в приложении не требуются более общую схему архивный объект для других целей.

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

  • Любой объект, который сериализуется с помощью прямого вызова Serialize не должны использовать CArchive::GetObjectSchema или, указывающее должен дескриптор возвращаемого значения (UINT) -1, что версия неизвестно.

Так как Serialize вызывается непосредственно в документе, не обычно может виды документов в архив ссылок на их родительский документ.Эти объекты должен быть указан указатель на документ-контейнер или необходимо использовать CArchive::MapObject функции сопоставления CDocument указатель PID, прежде чем эти обратные указатели, архивируются.

Как отмечалось ранее, следует кодировать версии и класса сведений вручную при вызове Serialize напрямую, что позволяет впоследствии изменить формат, сохраняя обратной совместимости с более старыми версиями файлов.CArchive::SerializeClass Функция может быть вызвана явным образом, прежде чем непосредственно сериализации объекта или до вызова метода базового класса.

См. также

Другие ресурсы

Технические замечания по номеру

Технические замечания по категориям