的方式修改的std::ostream
行为是不通过重载任何输出运算符!相反,您从std::streambuf
派生类并取代virtual
函数overflow()
和sync()
。在你的情况下,你可能会创建一个过滤流缓冲区,也就是说,你可以将另一个std::streambuf
作为参数,并向该流缓冲区中写入一个修改过的字符流。
下面是一个简单的例子:
#include <iostream>
class prefixbuf
: public std::streambuf
{
std::string prefix;
std::streambuf* sbuf;
bool need_prefix;
int sync() {
return this->sbuf->pubsync();
}
int overflow(int c) {
if (c != std::char_traits<char>::eof()) {
if (this->need_prefix
&& !this->prefix.empty()
&& this->prefix.size() != this->sbuf->sputn(&this->prefix[0], this->prefix.size())) {
return std::char_traits<char>::eof();
}
this->need_prefix = c == '\n';
}
return this->sbuf->sputc(c);
}
public:
prefixbuf(std::string const& prefix, std::streambuf* sbuf)
: prefix(prefix)
, sbuf(sbuf)
, need_prefix(true) {
}
};
class oprefixstream
: private virtual prefixbuf
, public std::ostream
{
public:
oprefixstream(std::string const& prefix, std::ostream& out)
: prefixbuf(prefix, out.rdbuf())
, std::ios(static_cast<std::streambuf*>(this))
, std::ostream(static_cast<std::streambuf*>(this)) {
}
};
int main()
{
oprefixstream out("prefix: ", std::cout);
out << "hello\n"
<< "world\n";
}
流缓冲概念性地保持一个内部缓冲器,该缓冲器是,然而,没有设置在上述的例子。每次没有将字符写入输出缓冲区的空间时,virtual
函数overflow()
被调用一个字符(也可以使用通常用于刷新缓冲区的特殊值std::char_traits<char>::eof()
来调用)。由于没有缓冲区,每个角色都会调用overflow()
。所有这些功能的作用是查看是否需要写入前缀,如果是,则写入prefix
。如果写入换行'\n'
,则该函数会记住如果写入另一个字符,则需要编写prefix
。然后它只是将字符的写入转发给基础流缓冲区。
virtual
功能sync()
用于同步流与其外部表示。对于保留缓冲区的流缓冲区,它确保写入任何缓冲区。由于prefixbuf
并不真正保留一个缓冲区,所以它只需要通过调用pubsync()
将sync()
请求委托给基础流缓冲区。
通常,从std :: stream派生它不是一个好主意 - 它没有虚拟析构函数,并且代码显示了输出操作在派生类中的效果如何,因为您正在返回对基类的引用。我会尝试扩展到一个完整的答案,除非有人打我:) – 2014-12-06 20:52:08
您的模板应该返回'parallel_cout&',而不是通用'ostream&'。 – Deduplicator 2014-12-06 20:52:15
@martin_pr'std :: ostream'有一个虚拟构造函数(继承自'std :: ios_base')。此外,'std :: fstream'和'std :: stringstream'也是派生类,但它们工作正常。你想从IOStreams基类派生的主要原因是环绕自定义的'std :: streambuf',这是具体的流类。 – 0x499602D2 2014-12-06 20:54:29