将常规类成员转换为静态类成员
我正在构建“系统”,以便稍后可以在“基于操作”的环境中编写。我想要的是给我的实例(即“汽车”)一定的状态(即停车,驾驶,起步)。那么在某些情况下,应该根据状态执行代码。将常规类成员转换为静态类成员
我不想使用一个开关/的if-then-else语句,因为这是很容易出错&难以扩展。 (为了允许更多的状态)。相反,我想使用函数指针。
我的代码(忽略的功能sillyness,他们证明):
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
enum State {Set, Add, Mul};
class car {
public:
typedef void (car::*MemFn)(int v);
car(int v, State _s) : val(v), s(_s) {
posFunctions.insert(std::make_pair(State(Set),&car::SetVal));
posFunctions.insert(std::make_pair(State(Add),&car::AddVal));
}
void DoIt(int v) {
//MemFn t = &car::SetVal;
MemFn t = posFunctions.find(s)->second;
CALL_MEMBER_FN(*this,t)(v);
}
int val;
State s;
protected:
std::map<State,car::MemFn> posFunctions;
void SetVal(int v) {
val = v;
}
void AddVal(int v) {
val += v;
}
void MulVal(int v) {
val *= v;
}
};
这个工程,我期望的那样。 (我可以调用创建一个汽车对象,给它一个特定的状态,然后调用“doit - 这将是该事件触发的功能”来执行这些操作)。
然而,有1件很烦人的事情:我创建函数映射(映射与功能的状态来执行),每节车厢的对象独立。这实际上并不“真实”(事实上,每个汽车在状态&事件相同时总是执行相同的操作),因此容易出错/难看。
我试图使“posFunctions”静态地图,并使用用于2线在构造的静态初始化功能。
main.obj:错误LNK2001:无法解析的外部符号 “受保护:静态类的std ::地图,一流的std ::分配器>>汽车:: posFunctions”?(posFunctions @汽车@@ 1V $ @地图W4State @@ P8car @@ @ AEXH ZU?$ @少@@@ W4State STD @@ V'$分配器@ U&$对@ $$ CBW4State @@ P8car @@ AEXH @ Z @ STD @@@ 4 @@性病@@ A) 我想这是因为我访问一个非静态成员函数 - 即使它是指向?
是它可能使地图静态(或全球)?
谢谢你的帮助, paul23
这是可能的 - 你必须在1处(本类最有可能的CPP文件)定义静态变量。
std::map<State,car::MemFn> car::posFunctions;
你在头文件中有哪些仅仅是一个声明。
这类似于你必须提供一个功能定义在每个.cpp文件的方式工作,你在头声明。如果你错过了任何函数体,连接器将会在每个缺少的函数上给出相同的错误。
要初始化按需这种结构,(如果需要在一个线程安全的方式)提供被从你的类构造函数,但检查称为静态成员函数,不管它是被称为前。
void car::initFunctions()
{
static bool done(false);
if (done)
return;
// first pass, set up the map
done = true;
}
你忘了在地图上定义一个全球范围内,即
std::map<State,car::MemFn> car::posFunctions;
。
一般来说,当你做出这样的结构时,问问自己 - 你可以用多态性来代替吗?
你的链接错误放在一边(其他人已经在下面回答了),你有没有考虑使用状态模式来建模?可能会做出更清晰的实施。 http://en.wikipedia.org/wiki/State_pattern – razlebe 2010-11-19 17:02:24
感谢大家的答案,我真的需要更加小心这些事情。 – paul23 2010-11-19 17:14:25
如果您的编译器没有它,请使用std :: function或boost :: function。 – 2010-11-19 17:16:45