2012-06-06 91 views
4

我想通過擴展std::streambuf來了解更多關於C++ I/O流庫的工作原理。作爲一個學習實驗,我的目標是簡單地創建一個自定義流,將所有輸出指向std::cerr。它似乎很簡單:擴展C++ ostream

#include <iostream> 
using namespace std; 

class my_ostreambuf : public std::streambuf 
{ 
    public: 

    protected: 

    std::streamsize xsputn(const char * s, std::streamsize n) 
    { 
     std::cerr << "Redirecting to cerr: " << s << std::endl; 
     return n; 
    } 

}; 

int main() 
{ 
    my_ostreambuf buf; 
    std::ostream os(&buf); 
    os << "TEST"; 
} 

這似乎工作,因爲它打印Redirecting to cerr: TEST。問題是它不起作用當一個單個字符(而不是一個字符串)通過std::ostream::sputc插入到流中時。例如:

int main() 
{ 
    my_ostreambuf buf; 
    std::ostream os(&buf); 
    os << "ABC"; // works 
    std::string s("TEST"); 
    std::copy(s.begin(), s.end(), std::ostreambuf_iterator<char>(os)); // DOESN'T WORK 
} 

我想這個問題是xsputn不處理單個字符插入。 (我猜sputc內部不會調用xsputn?)但是,看看list of virtual protected functionsstd::streambuf,我沒有看到任何我應該重寫的函數處理單個字符插入。

那麼,我該如何做到這一點?

回答

4

單字符輸出由overflow處理。下面是你可能在xsputn如果xsputn沒有實際輸出方面實現overflow

int_type overflow(int_type c = traits_type::eof()) 
{ 
    if (c == traits_type::eof()) 
     return traits_type::eof(); 
    else 
    { 
     char_type ch = traits_type::to_char_type(c); 
     return xsputn(&ch, 1) == 1 ? c : traits_type::eof(); 
    } 
} 
+0

那麼,什麼是處理'sputc'? – 0x499602D2

+0

@ 0x499602D2:'sputc'將一個字符寫入由streambuf維護的內部緩衝區。當緩衝區滿或者使用'endl'或'flush'操縱器時(以及其他一些情況),這個緩衝區會被刷新。當緩衝區被刷新時,如果下一個字符沒有被填滿,下一個字符將被調用'overflow'(或者如果緩衝區未滿時被刷新,則使用'eof')。這個想法是'overflow'將緩衝區的內容,以及作爲參數傳遞的字符(如果不是'eof')寫入實際的目的地。 (在下一條評論中繼續) – HighCommander4

+0

@ 0x499602D2:因此,可以通過覆蓋「overflow」來編寫一個正常運行的streambuf實現。一次輸出一串字符時使用'xsputn'。它的默認實現只是將每個字符寫入內部緩衝區,就像通過'sputc'(最終它們將被「overflow」處理)一樣。然而,'xsputn'可以被覆蓋,做一些更有效的操作,例如繞過緩衝區並直接將字符串寫入目的地。 – HighCommander4