我有以下的代码实现了一个基本的迈尔斯singletone:
#ifndef _cConfigFile_HH
#define _cConfigFile_HH
class cConfigFile {
public:
static cConfigFile& getInstance() {
static cConfigFile instance;
return instance;
};
private:
cConfigFile();
};
#endif
我的编译器不允许我编译此,给了以下错误:
/include/cConfigFile.hh:7: undefined reference to `cConfigFile::cConfigFile()'
从错误中我明白,我需要在.cpp文件申报“实例”,但我不能,因为编译器说来声明cConfigFile ::例如:
“cConfigFile cConfigFile ::比如”不是一个静态的
我究竟做错了什么?? 我在这里失去了..
第一个错误消息意味着你缺少实例的构造函数。
至于第二:这将是一个很好的主意,包括在.cpp代码在您试图定义实例。 但是,这听起来像你试图定义实例变量的类静态的,你不应该做的事。
实例化实例中一个.cpp,你想有这样的事情在你的.hh文件:
class cConfigFile {
public:
static cConfigFile& getInstance();
private:
cConfigFile() {} // Note: define the constructor -- this is probably not enough!
};
这在您的.cpp文件:
cConfigFile& cConfigFile::getInstance()
{
// Define the singleton as a local static
static cConfigFile instance;
return instance;
}
注意 :您真的要定义getInstance
在.cpp文件的方法,而不是作为一个内联函数。 其定义为内联会给你一个实例instance
在使用该头的每个.cpp文件。 这违背了试图使它单身的宗旨!
您需要在头文件的底部初始化静态实例:
cConfigFile cConfigFile ::实例;
而你需要把静态实例的声明中的getInstance()函数之外。
class cConfigFile{
public:
static cConfigFile instance; //declare
cConfigFile & getInstance(){
return instance;
}
private:
cConfigFile(){}
};
cConfigFile cConfigFile::instance(); //initialize
这不完全是一个答案,只是评论这是另一评论过长的响应,而这是有关这个问题。
请不要使用辛格尔顿。 您所陈述的理由这样做,你将用它来存储配置信息,并且该配置信息需要从程序的任何地方访问。
这是一个全局变量的原因(虽然,恕我直言,不一定一个伟大的),但不是一个Singleton的理由。 又有什么不好的存储现有配置多个对象? 如果所有用户使用的全局变量进行访问,他们都使用同一个。 为什么是有帮助的实例数量限制强行向一个?
其次,在未来会发生什么,当你需要临时增加一些配置选项? 某种程度上说,你的程序需要排序的运行本身作为一个子计划什么的配置稍有不同的信息,然后恢复原来的配置? 或者,也许你需要FROB配置在测试几种不同的方法,然后将其还原到原来的状态? 随着辛格尔顿和全局变量这将成为非常棘手。 但是,如果你使用一些更加灵活,这是非常容易的。
现在我个人认为,绕过配置选项,所有需要他们一个明确的时尚的东西不一定是坏的路要走。 但如果你认为这是无法忍受的,这里是一个另类:
template <typename T>
class DynamicallyScoped {
public:
explicit DynamicallyScoped(T &stackinstance) : oldinstance_(0) {
oldinstance_ = S_curinstance;
S_curinstance = &stackinstance;
}
~DynamicallyScoped() {
S_curinstance = oldinstance_;
oldinstance_ = 0;
}
static T *curInstance() { return S_curinstance; }
private:
static T *S_curinstance;
T *oldinstance_;
// Made private and left undefined on purpose.
DynamicallyScoped(const DynamicallyScoped &b);
const DynamicallyScoped &operator =(const DynamicallyScoped &b);
};
这使您可以替换当前实例的范围,当范围消失,系统将自动恢复。 它还允许你说DynamicallyScoped<Foo>::curInstance()->get_something();
随时随地在你的程序中,除了在构造函数静态或全局对象,并希望得到一些有用的东西。
这是一个涂鸦,并以这种形式可能是有用的。 但我可以想像,它可能是更好的方式。 例如,对于一些修改,你可以有多个相同类型的动态范围的变量。
实例:
#include <iostream>
template <>
int *DynamicallyScoped<int>::S_curinstance = 0;
extern void doSomething();
extern void doSomethingElse();
extern void printTheInt();
int main(int argc, char *argv[])
{
int x = 5;
DynamicallyScoped<int> theInt(x);
printTheInt();
doSomething();
doSomethingElse();
}
void doSomething()
{
printTheInt();
}
void doSomethingElse()
{
int newint = 6;
DynamicallyScoped<int> subint(newint);
doSomething();
}
void printTheInt()
{
::std::cout << "_The_ integer's value is: "
<< *DynamicallyScoped<int>::curInstance() << '\n';
}
至于那可以创造你的“全局配置文件”对象的多个实例的烦恼,不硬编码的文件名。 构造在对象main
作为堆栈变量,并给它的文件名作为参数。 再有,如果代码的其他部分创建配置文件对象的实例,除非他们也给全局配置文件的名称是没有问题的。 如果他们这样做,他们是自作自受。