出力する場合は、外部の(メンバ関数でない)関数でも記述できる。 しかし、入力する場合は(構築するわけだから)メンバ関数でないと 記述できないことがある。(あるいは、穴を開けることになる。)
だが、例えば、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でも使える。
t << m_i << ' ' << m_j; t >> m_i >> m_j;しかし、ストリームがCArchiveだとうまく行かない。そのときは、次のようにするとよい。
char c; t >> m_i >> c >> m_j;つまり、余分な文字をダミーの変数に入れてしまうのである。