灵活的记录器类,使用C++中的标准流

Pet*_*erK 5 c++ logging stream

我想创建一个灵活的记录器类.我希望它能够将数据输出到文件或标准输出.另外,我想使用流.该类应该类似于:

class Logger
{
private:
   std::ostream m_out; // or ofstream, iostream? i don't know
public:

   void useFile( std::string fname);
   void useStdOut();

   void log( symbol_id si, int val );
   void log( symbol_id si, std::string str );
   //etc..
};
Run Code Online (Sandbox Code Playgroud)

symbol_id是一个枚举并定义格式.我想要实现的是能够轻松地从非标准输出切换到一个文件中,反之亦然(这是的目的use*的方法).最好通过只使用m_out和简单地写m_out << "something";,没有任何检查我是否要写入一个文件或标准输出.

我知道有很多方法如何解决这个问题(使用if's到测试,如果我想要写一个文件或标准输出中,"C办法"(使用FILE*fprintf))等,但我敢肯定,一定有办法如何以一种很好的方式实现C++流.但我似乎无法找到如何做到这一点.有人可以帮帮我吗?

utn*_*tim 9

std::o*streamC++中的类继承自std :: ostream.这意味着你应该根据std :: ofstream指针或引用来编写你的接口:

class Logger
{
    std::ostream *m_out; // use pointer so you can change it at any point
    bool          m_owner;
public:
    // constructor is trivial (and ommited)
    virtual ~Logger()
    {
        setStream(0, false);
    }
    void setStream( std::ostream* stream, bool owner )
    {
        if(m_owner)
            delete m_out;
        m_out = stream;
        m_owner = owner;
    }
    template<typename T>
    Logger& operator << (const T& object)
    {
        if(!m_out)
            throw std::runtime_error("No stream set for Logger class");
        (*m_out) << object;
        return *this;
    }
};

// usage:
Logger logger;
logger.setStream( &std::cout, false ); // do not delete std::cout when finished
logger << "This will be logged to std::cout" << std::endl;
// ...
logger.setStream( 
    new std::ofstream("myfile.log", std::ios_base::ate|std::ios_base::app), 
    true ); // delete the file stream when Logger goes out of scope
logger << "This will be appended to myfile.log" << std::endl;
Run Code Online (Sandbox Code Playgroud)


the*_*ill 8

我以前就袭击这一问题的方法是使Logger抽象基类和创建独立FileLoggerOutStreamLogger类.然后创建一个CompositeLogger实现Logger接口的对象,它只输出所有记录器:

CompositeLogger compLogger;
compLogger.Add(new FileLogger("output.txt"));
compLogger.Add(new StreamLogger(std::cout));
...
compLogger.log(...);
Run Code Online (Sandbox Code Playgroud)

如果您不需要这种级别的灵活性并且希望将所有这些保留在单个类中,则可以使m_Out变量成为指针std::ostream并添加额外的标志以跟踪是否需要在清理时删除它:

private:
  std::ostream*   m_out;
  bool            m_OwnsStream;

Logger() {
   m_Out=&std::cout; // defaults to stdout
   m_OwnsStream=false;
}
void useFile(std::string filename) {
  m_Out=new std::ofstream(filename);
  m_OwnsStream=true;
}
~Logger() {
  if (m_OwnStream) 
    delete m_Out; 
}
Run Code Online (Sandbox Code Playgroud)

显然,你需要更多的检查useFileuseStdOut防止内存泄漏.