我想做类似以下代码的事情:
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
)。这不应仅适用于文件流,而应适用于所有其他流类。有没有简单的方法来允许这些功能?
答案 0 :(得分: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
。我希望在你的路上帮助你。
答案 1 :(得分: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);
}
};
答案 2 :(得分:2)
如果我理解正确,你想装饰任何iostream
的方法。所以,只需让你的装饰者把iostream
作为decoratee(而不是fstream
,它是iostream
的子类。)
答案 3 :(得分: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(...);
答案 4 :(得分:0)
此类问题的常用解决方案是使用模板。那里
并非std::istream
或std::ostream
which need covering, and a good template member for
&lt;&lt; and
&gt;&gt; should
cover a lot of the cases. In most of the cases I've done this, I've
only offerred
&lt;&lt; or
&gt; ;&GT;`。 (一般来说,我不需要
双向流。)
至于处理其他类型的流,只需使用std::iostream
std::fstream
。 (一般情况下,除了打开文件时,你
不应该看到fstream
部分。)