: 永続的なオブジェクト データ形式

このノートでは、それをファイルに保存されている場合は、永続的な C++ オブジェクトと、オブジェクトのデータの形式をサポートする MFC ルーチンについて説明します。これはクラスDECLARE_SERIALIMPLEMENT_SERIALマクロにのみ適用されます。

問題

Mfc の永続的なデータ ファイルの 1 つの連続した部分で多くのオブジェクトのデータを保存するため、コンパクトなバイナリ形式に依存します。このバイナリ形式の構造、データの格納方法は、提供しますが、それによってオブジェクトを保存実際のデータを提供するオブジェクトのSerializeメンバー関数。

MFC は、 CArchiveクラスを使用して、構造の問題を解決します。プログラマによって明示的にまたはCArchiveを含むスコープが終了したときに、デストラクターから暗黙的にCArchive::Closeメンバー関数が呼び出されるまで、アーカイブからの時間を持続持続性のコンテキストが作成されます、 CArchiveオブジェクトを提供します。

このノートでは、 CArchiveメンバー ReadObject WriteObjectの実装について説明します。ReadObjectWriteObjectにより直接呼び出されませんクラス固有のタイプ セーフな挿入および抽出演算子のDECLARE_SERIALIMPLEMENT_SERIALマクロによって自動的に生成されます。

いる CMyObject クラス: パブリック CObject{特価;DECLARE_SERIAL(CMyObject)};IMPLEMENT_SERIAL (された、CObject 1)//使用例 (ar は、CArchive &)いる CMyObject ※ pObj;CArchive & ar;ar << pObj;//ar を呼び出します。WriteObject(pObj)ar >> pObj;//ar を呼び出します。ReadObject(RUNTIME_CLASS(CObj))

このノートでは、MFC ソース ファイル ARCOBJ 内にあるコードについて説明します。CPP。メインのCArchive実装で ARCCORE を参照してください。CPP。

保存オブジェクト ストア (CArchive::WriteObject)

メンバー関数CArchive::WriteObjectオブジェクトを再構築に使用されるヘッダー データを書き込みます。このデータの 2 つの部分で構成されます: オブジェクトと、オブジェクトの状態の種類。このメンバー関数は、(循環ポインターなど) は、オブジェクトへのポインターの数に関係なく、1 つのコピーのみが保存されるように、書き込まれるオブジェクトの id を維持する責任も。

(挿入) を保存し、(抽出) オブジェクトを復元する依存いくつか「マニフェスト定数」。これらは、バイナリ形式で格納されているし、重要な情報アーカイブ ("w"プレフィックス 16 ビット量を示すメモ) を提供する値です。:

タグ 説明
wNullTag NULL オブジェクト ポインター (0) を使用。
wNewClassTag このアーカイブの context?(-1) に新しい次のようにクラスの説明を示します。
wOldClassTag 読み取り、オブジェクトのクラスはこのコンテキスト (0x8000) で見られていることを示します。

オブジェクトを保存するときは、アーカイブが格納されているオブジェクトから、32 ビットの永続的な識別子 (PID) へのマッピングは、 CMapPtrToPtr ( m_pStoreMap) を維持します。一意のすべてのオブジェクトとアーカイブのコンテキストに保存されているすべての一意のクラス名は、PID が割り当てられます。これらの Pid は 1 から順番に渡されます。これらの Pid 意義は、アーカイブの範囲外であるし、特に、レコード番号、または他の id のアイテムと混同しないようにすることに注意してくださいすることが重要です。

MFC バージョン 4.0 で、 CArchiveクラスから非常に大規模なアーカイブをサポートする拡張されました。以前のバージョンでは、数が 0x7FFE (32766) オブジェクトをアーカイブの制限、16 ビット数量は、PID をだった。Pid は今、32 ビットが、0x7ffe 場合を除き、16 ビットとして書き出されます。大規模な Pid は、32 ビット PID で続いて 0x7FFF として書き込まれます。この技術ファイルの下位互換性を維持します。

オブジェクト (通常はグローバル カーソル演算子) をアーカイブに保存を要求すると、NULL CObjectポインターのチェックが行われます。ポインターが NULL の場合は、wNullTag、アーカイブ ストリームに挿入されます。

シリアル化可能です、実際のオブジェクト ポインターがあるかどうか ( DECLARE_SERIALクラスはクラス) は、オブジェクトが既に保存されているかどうかを参照するには、 m_pStoreMapをチェックします。それがある場合は、私たちは、オブジェクトに関連付けられた 32 ビット PID を挿入します。

前に、オブジェクトが保存されていない場合が考慮しなければならない 2 つの可能性: オブジェクトと、オブジェクトの正確な型 (つまり、クラス) の両方がこのアーカイブ コンテキストに新しいですまたはオブジェクトをすでに見て、正確なタイプのです。私たちm_pStoreMap我々 を保存しているオブジェクトに関連付けられたCRuntimeClassオブジェクトに一致するCRuntimeClassオブジェクトのクエリ タイプを見られているかどうかを確認します。我々 はこのクラスの前に見た場合、 WriteObjectは、ビット単位の単独 wOldClassTag、このインデックスのタグを挿入します。CRuntimeClassこのアーカイブ コンテキストに新しい [ WriteObjectそのクラスに新しい PID を割り当てます、前に、 wNewClassTagの値によって、アーカイブに挿入。

このクラスの記述子は、 CRuntimeClassメンバー関数ストアを使用して、アーカイブに挿入されます。CRuntimeClass::Storeクラス (下記参照) のスキーマ番号と、クラスの ASCII テキスト名を挿入します。メモ ASCII テキスト名の使用がアプリケーション間でアーカイブの一意性を保証しません、したがって、破損を防ぐために、データ ファイルにタグをお勧めします。クラス情報の挿入、次、アーカイブ オブジェクトm_pStoreMapに置きクラス固有のデータをアーカイブに挿入するには、 Serializeメンバー関数を呼び出します。Serializeを呼び出す前にm_pStoreMapにオブジェクトを配置、オブジェクトの複数のコピーをストアに保存されてから防ぐ。

最初の呼び出し側 (通常はオブジェクトのネットワークのルート) を返す場合、近くにアーカイブが重要です。その他CFile操作される場合は、 CArchiveのメンバー関数Flushを呼び出す必要があります。そう失敗は、破損したアーカイブになります。

特価;この実装では、0x3ffffffe アーカイブ コンテキストあたりのハードに制限します。このユニークなオブジェクトと、1 つのアーカイブに保存することができます。 クラスの最大数を表すが、メモのファイルを 1 つにディスク アーカイブ コンテキストの無制限数を持つことができます。(&N)。

読み込みオブジェクト ストア (CArchive::ReadObject) から

(抽出) オブジェクトを読み込み、 CArchive::ReadObjectメンバー関数を使用して、 WriteObjectの逆です。としてをWriteObjectReadObject直接ユーザー コードによって呼び出されるない;ユーザー コードは、 ReadObject予想CRuntimeClassを呼び出し、タイプ セーフな抽出演算子を呼び出す必要があります。これは、演算の型の整合性を保証します。

WriteObject実装増加 Pid 割り当てから、1 から始まる (0 NULL オブジェクトとして既定です)、 ReadObject実装では、配列を使用してアーカイブ コンテキストの状態を保持できます。PID がm_pLoadArrayの現在の上限値よりも大きい場合、PID、ストアから読み取られると、[ ReadObjectに新しいオブジェクト (クラスの説明) に従っている知ってください。

スキーマ番号

クラスのIMPLEMENT_SERIALが発生したときに、クラスに割り当てられている、スキーマ番号は、クラスの実装の「バージョン」です。スキーマ クラスの実装を指します、倍の数を特定のオブジェクト (通常、オブジェクトのバージョンと呼ばれます) 永続的なされました。

有効時間をかけて、同じクラスの複数の異なる実装を維持するには、オブジェクトのSerializeメンバー関数の実装を変更すると、スキーマをインクリメント、implementation.nbsp の古いバージョンを使用して格納されているオブジェクトを読み込むことができますコードを記述するには(&N);

スキーマがメモリ内のクラスの説明のとは異なる、永続的なストアのスキーマ番号が検出されると、 CArchive::ReadObjectメンバー関数、 CArchiveExceptionがスローされます。それはこの例外から回復するは容易ではないです。

VERSIONABLE_SCHEMAを使用することができますまたはいたこの中から例外を維持するには、スキーマ バージョンをスローします。VERSIONABLE_SCHEMAを使用して、コードを適切なアクションのSerialize関数でCArchive::GetObjectSchemaからの戻り値をチェックして取ることができます。

直接の呼び出しをシリアル化します。

WriteObjectReadObjectの一般的なオブジェクト アーカイブ方式のオーバーヘッド必要または希望がない多くのケースがあります。これは、データには、 CDocumentのシリアル化の一般的なケースです。この場合、 Serializeメンバー関数CDocumentの直接抽出でないというか演算子を挿入します。ドキュメントの内容により一般的なオブジェクト アーカイブ方式を使用する可能性があります。

Serializeを直接呼び出す場合の長所と短所は次のとおりです。:

Serializeは直接文書に対して呼び出されるため、通常、親ドキュメントへの参照をアーカイブするには、文書のサブオブジェクトをことはできません。これらのオブジェクトへのポインターのコンテナー ドキュメントに明示的に与える必要があります。 またはCArchive::MapObject関数を使用してこれらバック ポインターが整理される前に、PID にCDocumentポインターをマップする必要があります。

上記のように、あなたのバージョン情報とクラス情報自分後まだ古いファイルとの下位互換性を維持しながら、形式を変更することができます Serialize を直接呼び出すときエンコードしてください。直接オブジェクトをシリアル化する前に、または基本クラスを呼び出す前に明示的に、 CArchive::SerializeClassRef関数を呼び出すことができます。

番号順テクニカル ノート|nbsp;カテゴリ別テクニカル ノート(&N)

Index