2010-12-06 31 views
3

我正在做記錄,我希望有某種類似於流發生的事情的事情,最好做的,而不是CLogger << "Testing, " << 1 << ",2,3\n";CLogger->log("Testing, %i,2,3", 1);自定義流到C++的方法?

我的問題是我會怎麼做呢?我不想直接創建一個流到標準輸出,因爲我想使用我自己的方法,其中包括編寫文件等。我已經考慮用一個特定的結構重載,這會將當前的流緩衝區刷新到一個方法,但我必須做CLogger << flush << "Test!\n";,這有點奇怪。

有誰知道如何做到這一點?

回答

12

如果所有你需要的是將某些日誌消息指向文件,你認爲std::ofstream

否則,我喜歡從std::ostream派生我的日誌類,所以我得到了所有的流善良。訣竅是將所有特定於應用程序的代碼放入關聯的streambuf類中。試想一下:

#include <iostream> 
#include <sstream> 

class CLogger : public std::ostream { 
private: 
    class CLogBuf : public std::stringbuf { 
    private: 
     // or whatever you need for your application 
     std::string m_marker; 
    public: 
     CLogBuf(const std::string& marker) : m_marker(marker) { } 
     ~CLogBuf() { pubsync(); } 
     int sync() { 
      std::cout << m_marker << ": " << str(); 
      str(""); 
      return std::cout?0:-1; 
     } 

    }; 

public: 
    // Other constructors could specify filename, etc 
    // just remember to pass whatever you need to CLogBuf 
    CLogger(const std::string& marker) : std::ostream(new CLogBuf(marker)) {} 
    ~CLogger() { delete rdbuf(); } 
}; 

int main() 
{ 
    CLogger hi("hello"); 
    CLogger bye("goodbye"); 

    hi << "hello, world" << std::endl; 
    hi << "Oops, forgot to flush.\n"; 
    bye << "goodbye, cruel world\n" << std::flush; 
    bye << "Cough, cough.\n"; 
} 

注:

  • 的CLogger構造函數可以把你需要的任何參數的使用 - 文件名,輸出語言,一個指向底層的日誌數據,等等。只需將數據傳遞到CLogBuf類。
  • 在響應std :: flush期間,會自動調用CLogBuf的sync()。
6

檢出operator <<,這是STL的流過載。

class CLogger 
{ 
public: 
    CLogger& operator << (const std::string& _rhs) 
    { 
     // work with it here 
     return *this; 
    }; // eo operator << 
}; // eo class CLogger 

編輯:

看到這個頁面,列出的ostream如何的std ::重載operator <<爲不同的類型:

http://www.cplusplus.com/reference/iostream/ostream/operator%3C%3C/

+0

我澄清了我的第一篇文章,我也想格式化。 – Jookia 2010-12-06 13:48:55

1

所有的operator<<()功能的類ostream定義,您可以繼承並實施其方法。

+1

我不*認爲*他正在使用ostream,我想他是在問* stream * *行爲。 – 2010-12-06 13:40:25

+0

正確 - 建議他應該從ostream繼承,實現接口,然後讓所有人的免費操作,而不是自己實現它們。 – 2010-12-06 13:43:34

+0

啊!我懂了。好答案! :) – 2010-12-06 13:49:12

2

實現一個代理對象,它爲操作員提供< <並將所有權標記傳遞給返回的代理對象。當擁有所有權標記的對象死亡時,您刷新流。

這樣做的一個簡單方法是將ostringstream包裝到代理中的auto_ptr中,並在代理的d-tor中auto_ptr不爲空時清除記錄器。

這會給你ostream的可能格式,但仍然會導致只有一個調用你的記錄器,我認爲這是真正的問題。

想的東西是這樣的:

class CLoggingProxy 
{ 
public: 
    template <class T> 
    CLoggingProxy operator<<(const T& rhs) 
    { 
    if (stream) 
     *stream << rhs; 
    return *this; 
    } 

    ~CLoggingProxy() 
    { 
    if (stream) 
     logger->log(stream->str()); 
    } 

private: 
    std::auto_ptr<std::ostringstream> stream; 
    CLogger* logger; 

    friend class CLogger; 
    CLoggingProxy(CLogger* logger) // call this e.g. from the logger to "start" input 
    : stream(new std::ostringstream), logger(logger) {} 
}; 
0

我只是去複製粘貼我目前執行的這個下面,它所有你需要(和處理之類的東西std::endl等)。 AMBROSIA_DEBUG是在調試版本中定義的宏,因此從理論上講,對於這個輸出類的每個調用都應該在發佈版本中省略(雖然沒有檢查過,但似乎將邏輯開銷保持在最低限度,功能基於QDebug功能, 。一點點增加礦井debugLevel的,這將讓你在你的代碼依賴於運行參數,通過手工篩選調試消息現在它也增加了空間的相同數量的每條消息前

// C++ includes 
#include <iostream> 
#include <string> 

typedef std::ostream& (*STRFUNC)(std::ostream&); 

#ifdef AMBROSIA_DEBUG 
    static int debugLevel; 
    const static int maxDebugLevel = 9; 
#endif 

class Debug 
{ 
public: 

    #ifdef AMBROSIA_DEBUG 
    Debug(const int level = 0) 
    : m_output(level <= debugLevel), 
     m_outputSpaces(true), 
     m_spaces(std::string(level, ' ')) 
    #else 
    Debug(const int) 
    #endif // AMBROSIA_DEBUG 
    {} 

    template<typename T> 
    #ifdef AMBROSIA_DEBUG 
    Debug& operator<<(const T &output) 
    { 
     if(m_output) 
     { 
      if(m_outputSpaces) 
      { 
       m_outputSpaces = false; 
       std::cerr << m_spaces; 
      } 
      std::cerr << output; 
     } 
    #else 
    Debug& operator<<(const T &) 
    { 
    #endif // AMBROSIA_DEBUG 
     return *this; 
    } 
    // for std::endl and other manipulators 
    typedef std::ostream& (*STRFUNC)(std::ostream&); 
    #ifdef AMBROSIA_DEBUG 
    Debug& operator<<(STRFUNC func) 
    { 
     if(m_output) 
      func(std::cerr); 
    #else 
    Debug& operator<<(STRFUNC) 
    { 
    #endif // AMBROSIA_DEBUG 
     return *this; 
    } 
private: 
#ifdef AMBROSIA_DEBUG 
    bool m_output; 
    bool m_outputSpaces; 
    std::string m_spaces; 
#endif // AMBROSIA_DEBUG 
}; 

用法示例:

int main() 
{ 
    debugLevel = 9; // highest allowed in my app... 
    Debug(4) << "This message should have an indentation of 4 spaces." << endl; 
    Debug(8) << "This is a level 8 debug message.\n"; 
    return 0; 
}