C ++ Decora classs de basic_iostream

Quiero hacer algo así como el siguiente código muestra:

class foo { private: std::fstream* m_stream; public: foo(std::fstream* stream) : m_stream(stream) { } foo& write(char const* s, std::streamsize count) { if (/*condition*/) { m_stream->write(s, count); } else { // ... } return *this; } foo& read(char* s, std::streamsize count) { if (/*condition*/) { m_stream->read(s, count); } else { // ... } return *this; } }; 

Debería agregar el mismo comportamiento a todos los methods similares (p. Ej. put ). Esto no debe aplicarse solo a las secuencias de files, sino a todas las demás classs de secuencias. ¿Hay alguna manera fácil de permitir estas funciones?

Muchos de los operadores de salida formateados ( operator<< ) escriben directamente en el búfer de flujo subyacente. Lo que debe hacer para lograr esto de manera general es derivar una class de std :: basic_streambuf que reenvía todos los datos a otro std :: basic_streambuf, y luego, opcionalmente, crear una implementación mínima de std :: basic_ostream para hacer que su transmisión buffer más fácil

No diría que esto es particularmente fácil, pero es la única manera de hacerlo de una manera que puede afectar a todos los types de transmisión.

Aquí hay un ejemplo de un búfer de flujo mínimo que reenvía a otro búfer de flujo (y realiza alguna transformación sin sentido solo para demostrar lo que puede hacer), y una secuencia de acompañamiento:

 #include <iostream> #include <streambuf> template<typename CharType, typename Traits = std::char_traits<CharType> > class ForwardingStreamBuf : public std::basic_streambuf<CharType, Traits> { public: typedef Traits traits_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::pos_type pos_type; typedef typename traits_type::off_type off_type; ForwardingStreamBuf(std::basic_streambuf<CharType, Traits> *baseStreamBuf) : _baseStreamBuf(baseStreamBuf) { } protected: virtual int_type overflow(int_type c = traits_type::eof()) { if( _baseStreamBuf == NULL ) return traits_type::eof(); if( traits_type::eq_int_type(c, traits_type::eof()) ) return traits_type::not_eof(c); else { CharType ch = traits_type::to_char_type(c); if( ch >= 'A' && ch <= 'z' ) ch++; // Do some meaningless transformation return _baseStreamBuf->sputc(ch); } } virtual int sync() { if( _baseStreamBuf == NULL ) return -1; else return _baseStreamBuf->pubsync(); } private: std::basic_streambuf<CharType, Traits> *_baseStreamBuf; }; template<typename CharType, typename Traits = std::char_traits<CharType> > class ForwardingStream : public std::basic_ostream<CharType, Traits> { public: ForwardingStream(std::basic_ostream<CharType, Traits> &stream) : std::basic_ostream<CharType, Traits>(NULL), _buffer(stream.rdbuf()) { this->init(&_buffer); } ForwardingStreamBuf<CharType, Traits>* rdbuf() const { return &_buffer; } private: ForwardingStreamBuf<CharType, Traits> _buffer; }; 

Esto se puede usar de manera simple:

 int main() { ForwardingStream<char> test(std::cout); test << "Foo" << std::endl; } 

Que daría salida a Gpp . Espero que te ayude en tu path.

¿Algo como esto?

  template <class Stream> class DecoratedStream { public: DecoratedStream(Stream* stream) : m_stream(stream) {} DecoratedStream& write(const char* data, int count) { m_stream->write(data, count); } }; 

Si te entiendo correctamente, quieres decorar los methods de cualquier iostream . Así que simplemente haga que su decorador tome un iostream como decoratee (en oposition a un fstream , que es una subclass de iostream ).

Tener un puntero dentro de una estructura, ya que su enfoque actual es peligroso y propenso a errores. En su lugar, simplemente derivar dichas classs de stream e implementar constructores básicos y ajustar sus methods personalizados, como write() .

 template<typename StreamType> class foo : StreamType { // wrapper constructors supporting StreamType() constructors foo& write(char const* s, std::streamsize count) { //... return *this; } }; 

Uso:

 foo<fstream> obj; obj.write(...); 

La solución habitual para este tipo de problema es utilizar templates. No hay muchas funciones en un std::istream o y std::ostream which need covering, and a good template member for << and >> should cover a lot of the cases. In most of the cases I've done this, I've only offernetworking should cover a lot of the cases. In most of the cases I've done this, I've only offernetworking << or >> `. (En términos generales, no he necesitado transmisiones bidireccionales).

En cuanto al event handling otros types de transmisiones, simplemente use std::iostream lugar de std::fstream . (En general, excepto cuando se abren files, no se debe ver la parte fstream ).