2011-12-09 59 views
8

Tôi có một lớp C++ mà tôi muốn giữ luồng được sử dụng để ghi nhật ký.Dòng C++ dưới dạng biến thành viên

Luồng có thể được đặt (và có thể đặt lại) sau khi xây dựng đối tượng.

Bạn có thể đặt luồng là std::cout hoặc dưới dạng luồng tệp để đăng nhập vào tệp hoặc dưới dạng chuỗi không làm gì hơn là bỏ qua dữ liệu (một loại /dev/null). Trong mọi trường hợp, nó phải là đối tượng loại ostream, mà tác giả của đối tượng có thể đặt lại bất kỳ lúc nào. Bản thân lớp này không biết gì về loại luồng cụ thể.

tôi có thể thực hiện điều này với một con trỏ đến một ostream, nhưng sau đó các cú pháp trở thành một chút khó chịu, cần phải sử dụng các nhà điều hành deref:

(*m_log) << "message"; 

hơn

m_log << "message"; 

Nhưng tôi có thể Không sử dụng tài liệu tham khảo, vì đối tượng luồng cần phải được đặt lại sau khi đối tượng đã được khởi tạo.

Có cách nào thanh lịch để đạt được điều này, tức là, tránh sử dụng con trỏ, nhưng vẫn có thể đặt lại sau khi xây dựng?

+2

Tại sao bạn không cung cấp một chức năng thành viên nhỏ trở về một tham chiếu đến luồng của mình? một cái gì đó dọc theo con đường: ostream & mlog() {return * m_log;}. Sau đó bạn sẽ viết: mlog() << "message"; – fjardon

+0

Sử dụng một con trỏ, và bắt đầu chức năng của bạn với 'std :: ostream & o = * m_log;'. –

+2

@fjardon: Tại sao bạn không cung cấp câu trả lời nhỏ như vậy? P – Xeo

Trả lời

9

Bạn có thể thiết lập lại suối: nhìn thấy nó sống trên 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

Đây là một giải pháp tốt, chính xác dọc theo những gì tôi đang tìm kiếm cho. Nó có thể được mở rộng đến (tùy ý) thêm một dòng thứ 2, ví dụ, tạo ra một T. Tôi sẽ uprate này ... nếu tôi có đủ danh tiếng. (: Cảm ơn. –

+0

Nếu bạn đang tìm kiếm các cơ sở như Tee-stream, hãy xem [Boost Iostreams] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/index. html? path = 1), ví dụ: [Tee Filter] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/functions/tee.html#tee_filter) kết hợp với [Pipelines] (http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/guide/pipelines.html) – sehe

4

Tại sao lại gặp rắc rối?

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

Thay vào đó, chỉ sử dụng log() << "blah\n";.

+1

Bạn có nghĩa là 'return * m_log;' trong hàm, tất nhiên. –

+1

@ James: Tôi không biết ý bạn là gì. ♪ – Xeo

+0

Không có * trong phương thức đăng nhập trước khi tôi vừa mới làm mới trang. –

Các vấn đề liên quan