永続オブジェクト

永続オブジェクトとは、オブジェクトをシリアライズして ファイルなどに入出力できるようになっているものである。
シリアライズのためのインターフェースを持てばいいのだが、 困った問題が発生することがある。

出力する場合は、外部の(メンバ関数でない)関数でも記述できる。 しかし、入力する場合は(構築するわけだから)メンバ関数でないと 記述できないことがある。(あるいは、穴を開けることになる。)

だが、例えば、MFCのCArchiveに対してシリアライズを行いたい場合、 クラスにCArchiveを認識させなければいけないが、これは汎用性に欠ける。 (UNIXではMFCなど使えないから、UNIXには持っていけない。)

解決法としては3案ほど考えられる。

最もスマートなのは、メンバ関数テンプレートを用いる方法であろう。

	template <class T> void Load(T& t){t >> m_i >> m_j;}
という具合に。しかし、メンバ関数テンプレートは現在の所、 殆どのコンパイラでサポートされてない。よって、これはあきらめるしかない。

2番目の方法は、正統派のやり方である。ストリームのための抽象クラスを用意して それをインターフェースにして行う方法である。(サンプル
但し、この方法は、面倒くさいし、使いたいストリームが拡張されたときに、 直さなければいけない。(例えば、stringがistreamをサポートした場合など。)

3番目の方法は、ちょっと邪道かもしれない。構築用のメンバ関数を用意するのである。 これは、穴となるかもしれないので、公開したくないのだが、それもできない。
具体的には、

	class AnyClass {
		...
		void Load(int i,int j){m_i = i; m_j = j;}
	};
	template <class T>
	T& operator>>(T& t,AnyClass& a)
	{
		int	i,j;
		t >> i >> j;
		a.Load(i,j);
	}
という感じになる。(operator<<の方は省略した。) この方法の方が、2番目よりも柔軟性があるのでこれがよいかもしれない。 これで、iostreamでもfstreamでもsstreamでもCArchiveでも使える。
coutなどに出力するときのことを考えるとデリミタを入れることになる。 デリミタが空白ならば、入力の場合殆ど問題にならない。
		t << m_i << ' ' << m_j;

		t >> m_i >> m_j;
しかし、ストリームがCArchiveだとうまく行かない。そのときは、次のようにするとよい。
		char	c;
		t >> m_i >> c >> m_j;
つまり、余分な文字をダミーの変数に入れてしまうのである。

戻る