我怎样才能创建我的单例常量的实例?
我正在尝试为 Ogre(一个开源 3D 引擎)的标准日志记录类制作一个包装器。 我希望它具有与 std::cerr 相同的语法,并且在 Linux 上运行时也输出到 cerr。 这就是我所拥有的:
#ifndef _LOGGER_H_
#define _LOGGER_H_
#ifndef _XSTRING_
#include <xstring>
#endif
#ifndef __LogManager_H__
#include "OgreLogManager.h"
#endif
class Logger
{
public:
static Logger* m_Instance;
static Logger* getInstance() { return m_Instance; }
static const Logger& getInstanceConst() { return *m_Instance; }
Logger& operator << (const std::string& a_Message)
{
m_Log.append(a_Message);
_CheckNewLine();
return *m_Instance;
}
Logger& operator << (const char* a_Message)
{
m_Log += a_Message;
_CheckNewLine();
return *m_Instance;
}
private:
std::string m_Log;
Logger()
{
m_Log = "";
}
void _CheckNewLine()
{
if (m_Log.at(m_Log.size() - 1) == '\n')
{
Ogre::LogManager::getSingleton().logMessage(m_Log);
#if OGRE_PLATFORM != PLATFORM_WIN32 && OGRE_PLATFORM != OGRE_PLATFORM_WIN32
std::cerr << m_Log;
#endif
m_Log.clear();
}
}
};
#endif
现在,这工作正常,并且这个单例在 .cpp 中实例化:
#include "logger.h"
Logger* Logger::m_Instance = new Logger();
当我想在多个标头中使用单例时,问题就出现了。 我在 game3d.h
中实例化它,几乎所有标头都包含该文件,如下所示:
Logger awesomelogger = Logger::getInstance();
不幸的是,这会给出有关尝试重新声明 awesomelogger
的标头的多个错误。
我想让它成为一个常量,这将使它消失,但这会引入新的错误。 这就是我尝试过的:
friend Logger& operator << (const Logger& a_Logger, const std::string& a_Message)
{
a_Logger.m_Log.append(a_Message);
a_Logger._CheckNewLine();
return *m_Instance;
}
我的问题是:如何使该类的实例成为常量,或者如何重写该类但仍然能够执行 awesomelogger << “输出”<< s_Stuff <<; “\n”;
I'm trying to make a wrapper for Ogre (an open source 3D engine) 's standard logging class. I want it to have the same syntax as std::cerr
, and also output to cerr when running on Linux. Here's what I have:
#ifndef _LOGGER_H_
#define _LOGGER_H_
#ifndef _XSTRING_
#include <xstring>
#endif
#ifndef __LogManager_H__
#include "OgreLogManager.h"
#endif
class Logger
{
public:
static Logger* m_Instance;
static Logger* getInstance() { return m_Instance; }
static const Logger& getInstanceConst() { return *m_Instance; }
Logger& operator << (const std::string& a_Message)
{
m_Log.append(a_Message);
_CheckNewLine();
return *m_Instance;
}
Logger& operator << (const char* a_Message)
{
m_Log += a_Message;
_CheckNewLine();
return *m_Instance;
}
private:
std::string m_Log;
Logger()
{
m_Log = "";
}
void _CheckNewLine()
{
if (m_Log.at(m_Log.size() - 1) == '\n')
{
Ogre::LogManager::getSingleton().logMessage(m_Log);
#if OGRE_PLATFORM != PLATFORM_WIN32 && OGRE_PLATFORM != OGRE_PLATFORM_WIN32
std::cerr << m_Log;
#endif
m_Log.clear();
}
}
};
#endif
Now, this works fine, and this singleton is instanced in a .cpp:
#include "logger.h"
Logger* Logger::m_Instance = new Logger();
The problem comes when I want to use the singleton in multiple headers. I instantiate it in game3d.h
, which is included by pretty much all the headers like this:
Logger awesomelogger = Logger::getInstance();
Unfortunately, this gives multiple errors about headers trying to redeclare awesomelogger
.
I want to make it a const, which would make that go away, but that introduces new errors. This is what I tried:
friend Logger& operator << (const Logger& a_Logger, const std::string& a_Message)
{
a_Logger.m_Log.append(a_Message);
a_Logger._CheckNewLine();
return *m_Instance;
}
My question is: how can I make an instance of this class constant OR how can I rewrite this class but still be able to do awesomelogger << "output" << s_Stuff << "\n";
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
与您的问题无关,但请注意,诸如
_LOGGER_H_
和__LogManager_H__
之类的名称在 C++ 中是保留的 - 您不允许在自己的代码中使用它们。 如果您不理解有关名称开头下划线(或任何地方的双下划线)的规则,请不要使用它们。现在,关于你的问题,记录器显然不是常量。 提供对单例的访问的经典方法是对此的一些变体:
Not to do with your question, but ote that names such as
_LOGGER_H_
and__LogManager_H__
are reserverd in C++ - you are not allowed to use them in your own code. If you don't understand the rules regarding underscores at the start of names (or double underscores anywhere), then don't use them.Now, regarding your question, a logger obviously isn't const. The classic way to provide access to a singleton is some variation on this:
您的 get_instance 方法返回 Logger* 而不是 Logger。
Your get_instance method returns Logger* not Logger.
创建一个指向 const 对象的 const 指针。
而不是
你在课堂上也需要很多相应的更正。
make a const pointer to a const object.
instead of
You'll need a lot of respective corrections in the class too.
一般来说,您的 Logger“m_Instance”实例应该是私有的。 并且您的函数“GetLogger()”应该检查“m_Instance”是否尚未实例化(如果没有实例化),然后返回m_Instance。
Generally speaking too, your instance of Logger "m_Instance" should be private. And your function "GetLogger()" should check if "m_Instance" has not been instantiated (if not instantiate it) then return m_Instance.
经典的辛格尔顿模式看起来像这样:
现在我们已经有了基本的模式。 您需要看起来像全局变量的东西来访问它。 最简单的方法是作弊,不使用全局引用,而是使用本地引用。
因此,在头文件中以及 Logger 类定义中添加以下内容。
这在包含标头的每个编译单元中声明了一个文件局部变量。
它已被初始化为引用单例记录器的实例。 因为您需要在使用之前包含该文件,所以它将始终在任何使用之前进行声明,从而保证以正确的顺序进行初始化。
在主文件中:
The classic singelton pattern looks like this:
Now we have the basic pattern out the way. You need what looks like a global variable to access it. The simplest way is to cheat and not have a global, but use a local reference.
So in the header file along with your Logger class definition add the following.
This declares a file local variable in every compilation unit that includes the header.
That has been initialized to refer to instance of the logger that is a singelton. Because you need to include the file before you can use it will always be declared before any usage and thus guranteed to be initialized in the correct order.
In main file:
由此听来:
您正在包含 game3d.h 的每个模块中创建一个
awesomelogger
的新实例,并且由于此声明具有外部链接时,这些名称将在链接时发生冲突。请参阅名称与文件范围的链接了解C++ 链接规则的解释。
更好的解决方案是无需创建
awesomelogger
变量,只需在需要的地方直接调用Logger::getInstance()
即可。It sounds from this:
That you are creating a new instance of
awesomelogger
in every module that includes game3d.h and since this declaration has external linkage, these names will collide at link time.See Linkage in Names with File Scope for an explanation of C++ linkage rules.
A better solution is to dispense with creating the
awesomelogger
variable and just callLogger::getInstance()
directly wherever you need it.