简单的C++日志记录类-ostream引用初始化

Simple C++ logging class - ostream reference initialization

本文关键字:-ostream 引用 初始化 记录 C++ 日志 简单      更新时间:2023-10-16

我在这里读到了几个类似的问题,这些问题已经得到了回答,但我还没有找到答案,所以在以重复形式结束之前请记住这一点:)。我想要一个带有Print()方法的简单Log对象。如果日志是在没有参数的情况下构建的,那么日志就是cout。否则,参数将描述要进行日志记录的文件。

(我怀疑问题的一部分在于理解所有stream类之间的关系。)

编译时,错误为:

Log.cpp:11:23: error: invalid initialization of reference of type ‘std::ofstream& {aka std::basic_ofstream<char>&}’ from expression of type ‘std::ostream {aka std::basic_ostream<char>}’

Log.h:

#ifndef LOG_H
#define LOG_H
#include <string>
#include <fstream>
class Log {
public:
    Log();
    Log(const char*, const char*);
    void Print(const char*  msg,...);
private:
    // instance contains a reference to ostream
    std::ofstream&  output_stream;
};
#endif

Log.cpp:

#include "Log.h"
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <fstream>
// Constructor w/no parms = log to cout
Log::Log() :
    output_stream(cout)
{}
// Constructor w/parms = log to file
Log::Log(const char* dir, const char* file) {
    string output_file_name = string(dir) + "/" + string(file);
    output_stream.open(output_file_name.c_str(), std::ofstream::out);
}
// Print() sends output to the stream (we'll do printf semantics later)
void
Log::Print(const char* msg,...) {
    output_stream << msg << endl;
}

cout不是ofstream类型,因此不能将ofstream引用绑定到它。output_stream应该是ostream&类型,这将允许它引用cout和文件流,因为ofstreamostream的子类。

此外,在用户提供文件名的情况下,引用仍然需要一些东西来引用,不能直接使用它。我建议您存储一个实际的ofstream对象(或unique_ptr<ofstream>),并使output_stream引用它。确保在类定义中的ostream引用之前声明ofstream对象,否则,当您尝试绑定初始化列表中的引用时,将有未定义的行为。或者,您可以使它成为一个指针,而不是引用,并在构造函数的主体中分配它。

我建议洗牌filebuf s或其他streambuf s。

#include <string>
#include <ostream>
#include <fstream>
class Log {
public:
    Log();
    Log(const char*, const char*);
    void Print(const char*  msg,...);
private:
    // instance contains a reference to ostream
    std::ostream  output_stream;
    std::ofstream _file;
};

cpp:

#include <iostream>
#include <string>
#include <fstream>
// Constructor w/no parms = log to cout
Log::Log()
    : output_stream(std::cout.rdbuf())
{}
// Constructor w/parms = log to file
Log::Log(const char* dir, const char* file) 
    : output_stream(nullptr)
{
    std::string output_file_name = std::string(dir) + "/" + std::string(file);
    _file.open(output_file_name.c_str(), std::ofstream::out);
    output_stream.rdbuf(_file.rdbuf());
}
// Print() sends output to the stream (we'll do printf semantics later)
void Log::Print(const char* msg,...) {
    output_stream << msg << std::endl;
}