【问题标题】:Is this preprocessor directive acceptable here?这个预处理器指令在这里可以接受吗?
【发布时间】:2014-03-07 01:05:04
【问题描述】:

有一个单例Logger 类,我觉得每次调用打印方法时都写Logger::GetInstance() 是丑陋的。我能想到的唯一解决方案是#define。有什么更好的吗,或者这个宏在这种情况下是否合理?

#include <iostream>
#include <fstream>

class Logger
{
public:

    static Logger& GetInstance();
    ~Logger();
    template <typename T>
    void   Print(const T &t);
    void   SetNewline(bool b);
    void   SetLogging(bool b);

private:

    Logger();
    Logger(const Logger&);
    void operator=(const Logger&);

    bool newline;
    bool log;
    std::ofstream file;
};

int main()
{
    #define logger Logger::GetInstance()
    logger.Print("Hello");
    //Logger::GetInstance().Print("Hello");
}

【问题讨论】:

  • 你为什么在main方法里面#define这个记录器呢? #define 不尊重范围。如果你只想要logger 可用,你也可以使用Logger&amp; logger = Logger::GetInstance()
  • 拥有每个需要记录的对象,在构造函数中调用GetInstance()并存储引用?
  • 有点离题,但我更喜欢将Logger 作为参数传递给任何需要记录的函数。创建记录器的单点将是主要功能。我不喜欢全局可用的可修改状态。
  • @Onur 我会考虑的。这只是我虚构练习的游乐场,我还不是系统设计师...... :)
  • 如果您将Logger 类设为接口(即抽象)并作为参考/(智能)指针传递,您可以轻松模拟记录器以进行单元测试等。您也不会遇到生命周期问题(想想另一个静态单例比记录器寿命更长但想要记录一些东西的情况......

标签: c++ preprocessor-directive


【解决方案1】:

请注意,由于您显然是在“本地”定义宏,因此 宏不尊重范围

为什么不只定义一个函数而不是一个宏:

inline
auto logger() -> Logger& { return Logger::GetInstance(); }

那么你就可以写了

logger().Print( "Hello" );

【讨论】:

  • +1,但为什么是尾随返回类型?我认为它在这里没有用处。
  • 我将其用作 singleunified 函数声明语法。为什么要使用多种语法?
  • 嗯,是的,更好,但仍然是函数调用语法。是的,我知道宏不尊重范围,我只是把它放在那里是为了让问题更清楚。
  • @angew 同意。如果不需要类型扣除,那是完全没有必要的。
【解决方案2】:

Cheers 和 hth 的两种选择。 - 阿尔夫的回答:

如果你在一个范围内多次需要它,你可以给记录器一个名字:

Logger& logger = Logger::GetInstance();

// ...

logger.Print("Hello, world");

或者您也可以将日志记录方法设为静态:

static void Logger::Print(const T &t) {
   Logger::GetInstance().Print(t);
}

然后静态调用它们:

Logger::Print("Hello world!");

您可能会争辩说,对于客户端而言,是否存在实例并不重要 - 构造函数是私有的,因此他们无论如何都无法创建自己的实例。因此,静态方法是否创建实例应该不是他们关心的问题。在这种情况下,拥有一个名为GetInstance 的公共方法实际上暴露了不相关的实现细节。

【讨论】:

  • 静态打印方法是目前所有建议中最好的方法。
  • 哇。存储引用我什至没有想到,我立刻想,好吧,不能在这里做作业。那就很清楚了,谢谢。
  • @Onur 是的,正如我正在考虑的那样,是否有任何情况,你有一个单例类,但你不能让它的方法静态?
  • 如果你愿意首先创建一个单例类,我不明白为什么它不能有一个静态接口。 [..]这条评论的其余部分有点长,所以我把它添加到答案中。
  • @Innkeeper 您始终可以使用仅静态接口,因为所涉及的唯一数据可通过静态方法访问。
猜你喜欢
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 2013-04-29
相关资源
最近更新 更多