假设我有一个名为“Logger”的课程。这个名字是自我解释的,它记录了东西。我有一个静态方法,它记录东西(Logger :: log(string msg))。 我想重载运算符<<,以便我可以执行以下操作:
Logger << "AW YEAH, I LOVE C++";
我试图这样做,但不能。我管理的是:
Logger l;
l << ":(";
...
我想做什么?如果是的话,怎么样?
提前谢谢你:)
答案 0 :(得分:1)
如果Logger
是一个类的名称,那么你当然不能这样做。使用像
Logger &log() {
static Logger l;
return l;
}
log() << "And the answer is" << 42;
答案 1 :(得分:1)
假设您想利用std::ostream
提供的输出运算符,您应该不尝试重置输出运算符!相反,您将创建一个合适的流缓冲区(即,从std::streambuf
派生的类),并在该类的overflow()
和sync()
方法中实现您的自定义输出逻辑。然后,您的记录器将派生自std::ostream
并初始化其基类以使用您的自定义流缓冲区。
答案 2 :(得分:0)
重载运算符在值上运行,而不在类型上运行。
也许你应该重命名你的类,然后创建一个合适的全局对象。例如:
<强> logger.h:强>
class mylogger { /* ... */ };
extern mylogger logger;
<强> logger.cpp:强>
#include "logger.h"
mylogger logger;
用法:
#include "logger.h"
logger << "Done";
小心全局初始化问题;虽然;查看std::cout
的实施方法以获得解决此问题的方法(例如,使用Schwartz计数器)。
答案 3 :(得分:0)
这是可能的,但您需要弄清楚您真正想要的界面。一种选择是让你的Logger
成为std::ostream
(继承),然后开箱即用。另一种方法是维护一个与std::ostream
无关(无继承)的记录器,但是您需要为要记录的任何和所有类型Logger& operator<<(Logger&,T const &)
提供T
。对于std::string
的具体情况,您可以这样做:
Logger& operator<<(Logger& logger, std::string const& msg) {
logger.log(msg); // need not be, and problably should be static
return logger;
}
使这个泛型涉及C ++中大多数通用代码使用模板:
template <typename T>
Logger& operator<<(Logger& logger, T const & obj) {
// do specific work based on the type, or a completely generic approach:
std::ostringstream st;
st << obj;
logger.log(st.str());
return logger;
}
此时您可能需要考虑添加对操纵器的支持,并且......如果您从这条路径开始,可能更有意义的是不在每个函数中创建std::ostringstream
,而是创建一个一个作为成员,然后将所有数据转储到该流中并使用一些操纵器来提取字符串并将其写入(例如在std::flush
或std::ends
上...)
template <typename T>
Logger& operator<<(Logger& logger, T const& obj) {
logger.stream << obj;
return logger;
}
Logger& operator<<(Logger& logger, std::ostream& (*manip)(std::ostream&)) {
logger.stream << manip;
if (manip == static_cast<std::ostream& (*)(std::ostream&)>(std::flush)) {
logger.write(); // flush to disk
}
return logger;
}
// add support for other manipulators...
然后你可能会开始想知道是否更容易拉出一些现成的日志记录库并只是使用它。