的方式修改的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