2011-06-17 58 views
4

我想要做的事,如下面的代码所示:C++装饰basic_iostream类

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; 
    } 
}; 

我需要相同的行为添加到所有类似的方法(例如put)。这不仅适用于文件流,而且适用于所有其他流类。有没有简单的方法来允许这些功能?

回答

5

许多格式化输出操作符(operator<<)直接写入基础流缓冲区。为了以一般方式完成此任务,您需要做的是从std :: basic_streambuf派生一个类,它将所有数据转发到另一个std :: basic_streambuf,然后可选地创建一个最小std :: basic_ostream实现来使用您的流缓冲更容易。

虽然我不会说这很容易,但它是唯一能够影响所有流类型的方法。

这里是转发到另一个流缓冲区(和执行一些毫无意义的转变只是证明你能够做什么)的最小流缓冲区的例子,并伴随流:

#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; 
}; 

这可以用于很简单:

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

哪个会输出Gpp。我希望这可以帮助你。

2

这样的事情?

template <class Stream> 
    class DecoratedStream { 
    public: 
     DecoratedStream(Stream* stream) : m_stream(stream) {} 

     DecoratedStream& write(const char* data, int count) { 
     m_stream->write(data, count); 
     } 

    }; 
+0

没有必要。只需使用`iostream`,而不是`fstream`。 – 2011-06-17 12:06:06

2

如果我的理解正确,您想装饰任何iostream的方法。所以,只要让你的装饰者以iostream作为装饰(而不是fstream,这是iostream的子类)。

+0

+1。更好。这样它将适用于所有I/O流。 – Nawaz 2011-06-17 11:15:24

+0

除了相当多的`operator <<`函数直接输出到流使用的`std :: basic_streambuf`,并因此完全绕过这个修改。 – Sven 2011-06-17 11:17:42

+0

@Sven:是吗?我没有意识到这一点。但是,在这种情况下,OP的整个方法将是无效的,因为无论你如何做,装饰溪流都是不够的。 – 2011-06-17 11:21:38

0

将指针放在结构中,因为您当前的方法很危险并且容易出错。相反,只需派生类stream类并实现基本的构造函数,并包装您的自定义方法,如write()

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

用法:

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

对于这类问题通常的解决方法是使用模板。有 不是一个std::istream或与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 offerred < < or >>`很多功能。 (一般来说,我不需要 双向流。)

至于处理其他类型的流,只需使用std::iostream代替 的std::fstream。 (一般来说,除了打开文件时, 不应该看到fstream部分。)