在其他非相关类中使用C ++ Log类

时间:2015-09-14 14:14:13

标签: c++ logging ostream

我有一个C ++ Log类(实现很长,可能并不重要),我已经重载了&lt;&lt;运算符所以我可以使用像var val = $("#" + field + " option[text='" + value + "']"); 这样的语句来使它更直观(并允许我将输出分成屏幕和日志,如果需要的话)。这个班很好;我在log << "Error" << endl;中实例化它,可以毫无问题地使用它。我希望能够在其他非相关类中使用它而不实际将它传递给它们(通过类构造函数或类似),因为如果我通过副本,我最终运行某些管家日志类方法两次,如果我通过引用传递,我必须取消引用外部类中的指针才能使用它(Main())。这可能吗?最好的方法是什么?

4 个答案:

答案 0 :(得分:1)

使用以下声明创建一个全局函数:

Log& log();

它的实现可能如下所示:

Log& log()
{
    static Log log;
    return log;
}

或者像这样,避免破坏顺序问题(当具有静态存储持续时间的另一个对象的析构函数向日志写入内容时可能会发生这种情况):

Log& log()
{
    static Log* log = new Log; // never deleted
    return *log;
}

然后,您可以使用与以前语法几乎相同的记录器:

#include "log.h"

// ...

void f()
{
    log() << "Error\n";
}

与Singleton方法相比,这有两个优点:

  • 这更简单。
  • 它将日志类(写日志消息)的实际关注点与特定分配策略分开。

顺便说一句......

  

因为如果我通过副本,我最终会运行某些管家日志   类方法两次

不确定您的意思,但如果您通过副本传递,那么该类需要是可复制的,并且复制一个封装或访问外部资源的记录器通常没有意义。这就是标准流类(std::ostream等)不可复制的原因。

  

如果我通过引用传递,我必须取消引用外部类中的指针才能使用它

没有。你混淆了指针和引用。它们是完全不同的语言功能。解除引用是指针,而不是引用。

答案 1 :(得分:0)

我知道面向对象纯粹主义者反对以下想法的所有原因,但它对于我在各种大型项目中的日志记录和类似活动都很有效。它避免了其他设计中的许多实际问题:

使用纯虚方法创建一个基类,用于日志类可以执行的操作。创建基类的静态成员,该成员将是指向该类的单例实例化的指针,该指针由构造函数填充,并由静态访问器方法提供。所以你通常用它作为:

 base_logger::singleton() << whatever...

实际的logger类构造一次(在第一次使用之前方便的地方),它隐式调用base_logger构造函数锁定指向自身的指针,该指针将作为singleton()函数的引用返回。

您可能希望base_loggersingleton使用不同的名称。我只是描述它如何组合在一起以方便使用,而不是建议这些名称。

答案 2 :(得分:0)

您可以做的一件事是使用静态单例设计模式制作记录器类。

这意味着它只创建了一个实例(通常在logger.cpp编译单元中的静态存储持续时间),并且有一个全局可见的类logger静态方法,它返回对此的引用。然后,你不需要将对象传递给构造函数或函数或其他任何地方 - 无论你想在哪里使用它,你都可以简单地抓住单例。

如果过度使用,这种模式通常被认为是有害的。但是,对于记录器实用程序来说,它似乎非常合适 - 记录器可以合理地被认为是应用程序级资源,可以适当地绑定到程序的生命周期。单例模式可能会让创建正确的单元测试变得很痛苦,但通常您也不会非常关注单元测试记录器框架 - 如果您的日志消息通常无法正常工作,那么您通常会发现那就是马上。

答案 3 :(得分:0)

我会尽量简单,并实例化一个全局Log对象(实际上不是单例):

Log log;

并在公共头文件中声明extern

extern Log log;

有了这个,您可以在任何地方使用现有的语法。