用于日志记录目的的重载 cout
Overloading cout for logging purposes?
我想定义一些类似新cout的东西,我可以用来记录我的数据:
some_type cout2( Message_type message ){
cout << message;
logfile.save(message);
}
所以我会用它
cout2 << "some message" << endl;
到目前为止,我无法找出上面的代码必须是什么样子的。
感谢您的帮助。
您可以创建自己的记录器,如下所示:
class Logger {
public:
Logger(std::string const& filename)
: stream_(filename, std::ofstream::out | std::ofstream::app)
{
if (!stream_) {
// Error...
}
}
Logger& operator<<(std::string const& str) {
std::cout << str;
stream_ << str;
return *this;
}
private:
std::ofstream stream_;
};
一般来说,来自标准库C++类不是为派生而设计的,对于流类也是如此。
所以恕我直言,最好指定cout2
对象需要什么方法,然后:
- 设计一个包含
ostream&
对象的类,在 CTOR 中初始化 - 将实际输出委托给该内部对象
- 在方法中执行所需的任何日志
应使用模板化operator <<
以便能够轻松处理std::ostream
可以处理的任何类。
class LogStream {
std::ostream& out;
Logfile logfile;
LogStream(std::ostream& out, /* param for logfile initialization */ ...)
: out(out), logfile(...) {}
... // other useful methods for state
};
template<typename T>
LogStream& operator << (LogStream& out, T val) {
out.out << message;
// should first test whether T is manipulator, and choose whether and how it should be logged
logfile.save(message);
}
您不想修改std::cout
.
相反,您希望创建一个专用std::streambuf
,用于写入两个缓冲区而不是一个缓冲区。 例如;
#include <streambuf>
template <typename char_type,
typename traits = std::char_traits<char_type> >
class basic_teebuf:
public std::basic_streambuf<char_type, traits>
{
public:
typedef typename traits::int_type int_type;
basic_teebuf(std::basic_streambuf<char_type, traits> * sb1,
std::basic_streambuf<char_type, traits> * sb2)
: sb1(sb1)
, sb2(sb2)
{
}
protected: // override virtuals inherited from std::basic_streambuf
virtual int sync()
{
int const r1 = sb1->pubsync();
int const r2 = sb2->pubsync();
return r1 == 0 && r2 == 0 ? 0 : -1;
}
virtual int_type overflow(int_type c)
{
int_type const eof = traits::eof();
if (traits::eq_int_type(c, eof))
{
return traits::not_eof(c);
}
else
{
char_type const ch = traits::to_char_type(c);
int_type const r1 = sb1->sputc(ch);
int_type const r2 = sb2->sputc(ch);
return
traits::eq_int_type(r1, eof) ||
traits::eq_int_type(r2, eof) ? eof : c;
}
}
private:
std::basic_streambuf<char_type, traits> * sb1;
std::basic_streambuf<char_type, traits> * sb2;
};
typedef basic_teebuf<char> teebuf;
然后,您需要创建一个使用此类缓冲区的专用ostream
#include <ostream>
class teestream : public std::ostream
{
public:
// Construct an ostream which tees output to the supplied
// ostreams.
teestream(std::ostream & o1, std::ostream & o2);
private:
teebuf tbuf;
};
teestream::teestream(std::ostream & o1, std::ostream & o2)
: std::ostream(&tbuf)
, tbuf(o1.rdbuf(), o2.rdbuf())
{
}
以上所做的只是创建一个使用我们专用缓冲区的专用std::ostream
,而专用缓冲区又使用两个缓冲区。
现在,我们的teestream
需要使用两个流进行初始化。 例如
#include <fstream>
#include <iostream>
// include the preceding definition of teestream here
int main()
{
std::ofstream logfile("hello-world.log");
teestream tee(std::cout, logfile);
// tee is now a stream that writes the same output to std::cout and logfile
tee << "Hello, world!n";
return 0;
}
这样做的好处是所有流插入(运算符 <<
(都可以使用我们的teestream
- 即使对于具有重载版本的类也是如此。
当main()
返回时,溪流也将干净地关闭。
我已经将规范的streambuf
编写为模板(std::streambuf
是名为std::basic_streambuf
的模板化类的专业化(。 为了通用性,最好对流做同样的事情(使用std::ostream
也是模板化std::basic_ostream
的专用化这一事实(。 我把这种概括作为一种练习。
我见过的基于这个想法构建的日志记录系统看起来像这样:
#define MY_PRINT(x, ...)
{
fprintf(logFile, x, ##__VA_ARGS__);
fflush(acuLogFile);
}
你会像这样使用它:
MY_PRINT("this is just a testn");
尽管这是 C 的做事方式,但它非常通用,也可以在C++中工作。
您只需要在代码中的任何位置使用新定义的打印函数即可。
也许你应该有一个基于实例的记录器,它有一个.log()
方法,根据实现可以记录到文件,写入stdout等,而不是尝试从命名空间重载std
自由函数?
你的意图会更清晰,它会更面向对象。
事实上,这是我最近写的一个非常千篇一律的事件记录器的例子,如果这有助于你理解我所说的那种事情。我的设计允许依赖注入,以及在记录器中保留关于如何格式化为输出以及应该去哪里(stdout 或文件等(的无聊决策。
您可以定义自己的cout。首先,您需要一个可以处理<<运算符并包含 fstream 和 ostream (如 cout(的类。
class logstream
{
private:
fstream *filestream;
ostream *cout;
public:
logstream(fstream* filestream, ostream* cout)
{
this->cout = cout;
this->filestream = filestream;
}
string operator<< (char* s)
{
*cout << s;
*filestream << s;
return s;
}
};
要使用它,只需使用 cout 和 fstream 初始化它。
fstream lout = fstream("Filename", ios::app);
logstream cout = logstream(&lout, &std::cout);
现在你得到了你想要的。
cout << "message";
编辑:不要忘记包括
#include <iostream>
#include <fstream>
和
using namespace std;
- 使用模板类重载 cout
- cout (<<) 重载运算符不打印减去的矩阵
- 重载运算符 (<<) cout 在 c ++ 中不起作用,当我互相减去两个矩阵时不起作用
- 使用 cout 运算符重载字符串
- std::cout 不适用于结构的重载"<<"运算符
- 为什么当我使用额外的括号而不使用运算符重载时,插入运算符在 std::cout 中给出不同的结果?
- & 字符在重载 std::cout 中的功能是什么?
- 错误:与 std::cout 中的运算符<<不匹配(我已经重载了 << 运算符)
- 如何重载模板类<< cout? 轨道结帐表单/视图:用户输入>查看输入>结帐
- cout <<棘手的运算符重载 - 转储结构的字节数
- 重载左移和右移运算符(cin和cout)
- 重载cout时未定义引用
- 在C++重载cout ostream操作员
- 如何为我的对象重载 cout
- C++ 随机 COUT 语句导致程序在重载的"="运算符内崩溃
- 将cout重载为非好友助手运算符
- 运算符重载似乎对cout起到了双向作用
- 用于日志记录目的的重载 cout
- 操作符重载- cout和cin——ostream函数,不能被引用——它是一个已删除的函数
- 运算符重载 - 如何在C++中重载 cout 行为