2011-12-09 91 views
8

我有一個C++類,我想持有一個用於記錄的流。C++流作爲成員變量

在構建對象之後,應該能夠設置流(並可能重置)。

應該可以將流設置爲std::cout,或者將文件流設置爲記錄到文件,或者作爲只會忽略數據(僅排序的/dev/null)的字符串流。無論如何,它應該是一個ostream類型的對象,對象的創建者可以隨時重置它。這個類本身對於具體的流類型是沒有意義的。

我可以用一個指針指向一個ostream做到這一點,但隨後的語法變得有點討厭,不必使用DEREF操作:

(*m_log) << "message"; 

而不是

m_log << "message"; 

但我做不到不使用引用,因爲在初始化對象之後,流對象可能需要重置。

是否有一個優雅的方式來實現這一點,即避免使用指針,但仍然能夠在施工後重置?

+2

你爲什麼不提供一個小成員函數返回到您的流的參考?沿途的東西:ostream&mlog(){return * m_log;}。然後你會寫:mlog()<<「message」; – fjardon

+0

使用一個指針,並用'std :: ostream&o = * m_log;'開始你的函數。 –

+2

@fjardon:你爲什麼不提供這個小答案? ; P – Xeo

回答

9

可以重置流:看到它住在https://ideone.com/Ci4eo

#include <fstream> 
#include <iostream> 
#include <string> 

struct Logger 
{ 
    Logger(std::ostream& os) : m_log(os.rdbuf()) { } 

    std::streambuf* reset(std::ostream& os) 
    { 
     return m_log.rdbuf(os.rdbuf()); 
    } 

    template <typename T> friend Logger& operator<<(Logger& os, const T& t) 
    { os.m_log << t; return os; } 

    friend Logger& operator<<(Logger& os, std::ostream& (*pf)(std::ostream&)) 
    { os.m_log << pf; return os; } 

    private: 
    std::ostream m_log; 
}; 

int main(int argc, const char *argv[]) 
{ 
    Logger logto(std::cout); 

    logto << "Hello world" << std::endl; 

    logto.reset(std::cerr); 
    logto << "Error world" << std::endl; 

    return 0; 
} 
+0

這是一個很好的解決方案,完全符合我期待的內容對於。它可以擴展到(可選)添加第二個流,例如創建一個T.如果我有足夠的聲望,我會提高這個...。 (:Thanks。 –

+0

如果您正在尋找Tee-streams等設施,請查看[Boost Iostreams](http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/index。 html?path = 1),例如[Tee Filter](http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/functions/tee.html#tee_filter)與[Pipelines] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/guide/pipelines.html) – sehe

4

爲什麼要麻煩你自己?

class foo{ 
public: 
    // .. 
private: 
    std::ostream& log() const{ return *m_log; } 
    mutable std::ostream* m_log; 
}; 

而只是使用log() << "blah\n";來代替。

+1

你的意思是'返回* m_log;'在函數中,當然。 –

+1

@詹姆斯:我不知道你的意思。 ♪ – Xeo

+0

在我刷新頁面之前,日誌方法中沒有*。 –