シリアル化 : シリアル化可能なクラスの作成
シリアル化可能なクラスを作成するには、次の 5 つの手順の作業が必要です。 ここでは、各手順の作業について説明します。
CObject からクラスを派生します (または、CObject の派生クラスから)。
Serialize メンバー関数をオーバーライドします。
クラス宣言で DECLARE_SERIAL マクロを使います。
引数を持たないコンストラクターを定義します。
クラスの実装ファイルで IMPLEMENT_SERIAL マクロを使います。
CArchive クラスの入出力ストリーム演算子 (>> または <<) を使わずに直接 Serialize を呼び出すときは、手順 3、4、5 は必要ありません。
CObject からのクラスの派生
シリアル化の基本的な操作と機能は CObject クラスに定義されています。 次のクラス CPerson の宣言例のように、CObject (またはその派生クラス) の派生クラスを作成すると、CObject のシリアル化操作と機能を利用できるようになります。
Serialize メンバー関数のオーバーライド
オブジェクトの現在の状態を取り込むために必要なデータを実際にシリアル化しているのは、CObject クラスで定義されている Serialize メンバー関数です。 Serialize 関数は CArchive 型引数を受け取り、これを使ってオブジェクト データを読み書きします。 CArchive オブジェクトは IsStoring メンバー関数を持ち、これによってシリアル化操作として格納 (データの書き込み) を行うのか、読み込み (データの読み取り) を行うのかを判定します。 IsStoring が返す結果に基づき、出力ストリーム演算子 (<<) を使ってオブジェクト データを CArchive に出力するか、入力ストリーム演算子 (>>) を使ってデータを入力するかを判断します。
例として、CString 型と WORD 型の 2 個のメンバー変数が追加された CObject 派生クラスを考えます。 次に示すクラス宣言部には、2 つの新しいメンバー変数とオーバーライドされた 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 を呼び出して、オブジェクトの継承部分をシリアル化します。
派生クラス固有のメンバー変数を出力または入力します。
出力ストリーム演算子と入力ストリーム演算子は、アーカイブ クラスを通じてデータの読み取りと書き込みを行います。 上の例で宣言された 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::Read メンバー関数と CArchive::Write メンバー関数も使用できます。
DECLARE_SERIAL マクロの使用
DECLARE_SERIAL マクロは、次のように、シリアル化可能なクラスを宣言するときに使います。
class CPerson : public CObject
{
public:
DECLARE_SERIAL( CPerson )
引数を持たないコンストラクターの定義
MFC では、オブジェクトを逆シリアル化して (ディスクから読み込んで) 復元するとき、既定のコンストラクターが必要になります。 この逆シリアル化処理によって、すべてのメンバー変数に値が代入され、オブジェクトが復元されます。
このコンストラクターは、public、protected、または private のいずれかとして宣言できます。 protected または private として宣言したコンストラクターは、シリアル化関数以外では使うことができません。 コンストラクターは、必要に応じて、オブジェクトを破棄できる状態にする必要があります。
注意
DECLARE_SERIAL マクロと IMPLEMENT_SERIAL マクロを使うクラスに対して引数のないコンストラクターを定義しておかないと、IMPLEMENT_SERIAL マクロを使用している行で、既定のコンストラクターがないことを示すコンパイラ警告メッセージが出力されます。
実装ファイルでの IMPLEMENT_SERIAL マクロの使用
IMPLEMENT_SERIAL マクロは、シリアル化可能な CObject 派生クラスを作るときに必要なさまざまな関数を定義します。 このマクロはクラスの実装ファイル (.CPP) の中に記述します。 マクロの先頭の 2 つの引数は、クラス名と直接基本クラス名です。
このマクロの 3 番目の引数はスキーマ番号です。 スキーマ番号は、本来、クラスのオブジェクトのバージョン番号です。 スキーマ番号には 0 以上の整数を使います。 この番号は、データベース用語のスキーマ番号とは異なります。
MFC のシリアル化処理の中で、オブジェクトをメモリに読み込むときにスキーマ番号がチェックされます。 ディスク上のオブジェクトのスキーマ番号がメモリ上のクラスのスキーマ番号と一致しないと、例外 CArchiveException がスローされます。この機構により、間違ったバージョンのオブジェクトは読み込まれません。
複数のバージョンのファイル、つまりアプリケーションの複数のバージョンで作成されたファイルを読み込むことができる Serialize メンバー関数を作成するには、IMPLEMENT_SERIAL マクロの引数として VERSIONABLE_SCHEMA を使います。 この使い方と例については、CArchive クラスの GetObjectSchema メンバー関数を参照してください。
次の例は、CObject 派生の CPerson クラスにおける IMPLEMENT_SERIAL マクロの宣言方法を示しています。
IMPLEMENT_SERIAL( CPerson, CObject, 1 )
シリアル化可能なクラスがあると、記事で説明したように、クラスのオブジェクトをシリアルできますシリアル化:オブジェクトのシリアル化。