以前の記事の続きということで、多少は役に立つオリジナル入出力クラスを作ることを考えてみます。最終的には書き込んだデータに何らかの加工を施して他のストリームに書き出すクラスを作る予定です。
こういうクラスを作る場合、最初に作るのはDecoratorクラスです。
これは、データを加工せずに他のストリームに書き出すクラスです(詳細についてはGoFのデザインパターンを見て下さい)。
加工しないのでこのクラス単体では何の役にも立ちませんが、加工をするようなクラスを作る際、このクラスを派生させて作ると楽に作れるのです。
Decoratorクラスの名前はbasic_filterbufとします。filterという名前はJavaのFilterInput/OutputStreamから貰いました。
コードは次のようになります。
(注意)本コードは正しく動作しません。詳細は「C++ストリームの拡張方法について」を参照して下さい。
template <class Elem, class Tr = std::char_traits<Elem> > class basic_filterbuf : public std::basic_streambuf<Elem, Tr> { public: explicit basic_filterbuf(std::basic_streambuf<Elem, Tr>* _Buffer, bool _Delete = false) : _buffer(_Buffer), _delete(_Delete) { } virtual ~basic_filterbuf(void) { if (_delete) { delete _buffer; } } protected: virtual void imbue(const std::locale &_Loc) { _buffer->pubimbue(_Loc); } virtual std::basic_streambuf<Elem, Tr>* setbuf(char_type* _Buffer, std::streamsize _Count) { _buffer->pubsetbuf(_Buffer, _Count); return this; } virtual pos_type seekoff(off_type _Off, std::ios_base::seekdir _Way, std::ios_base::openmode _Which = std::ios_base::in | std::ios_base::out) { return _buffer->pubseekoff(_Off, _Way, _Which); } virtual pos_type seekpos(pos_type _Sp, std::ios_base::openmode _Which = std::ios_base::in | std::ios_base::out) { return _buffer->pubseekpos(_Sp, _Which); } virtual int sync() { return _buffer->pubsync(); } virtual std::streamsize xsgetn(char_type* _Ptr, std::streamsize _Count) { return _buffer->sgetn(_Ptr, _Count); } virtual std::streamsize xsputn(const char_type* _Ptr, std::streamsize _Count) { return _buffer->sputn(_Ptr, _Count); } std::basic_streambuf<Elem, Tr>* buffer(void) { return _buffer; } private: std::basic_streambuf<Elem, Tr>* _buffer; bool _delete; };
なんとなく命名規則をVisualC++.NET 2003付属の標準ライブラリと合わせて見ました。
内容はそれほど難しいものではないと思いますので説明は省略します。 でもって上記しましたがこのクラス単体では役に立たないので使い方も省略します。
投稿者 MASATO : 2005年02月25日 23:11 | トラックバック