我有一个非常简单的类定义如下:
#include "../bshttp/controllers.h"
#include <iostream>
#include <string>
class DerivedController : public BS_Controllers
{
public:
DerivedController():BS_Controllers(this)
{
m_urlRules["print"] = REG_NAME &DerivedController::print;
//regController(REG_NAME &DerivedController::print,"print");
regController(REG_NAME &DerivedController::printView,"printView");
}
void * print()
{
return NULL;
}
void * printView()
{
cout<<"Print view!"<<endl;
return NULL;
}
};
其中
m_urlRules["print"] = REG_NAME &DerivedController::print;
或
regController(REG_NAME &DerivedController::printView,"printView");
必须为所有成员函数调用。是什么呢,它需要类的成员函数指针并用字符串映射,所以稍后可以用字符串识别函数。
一切都很好并且正常工作,但是当类结构变大时,程序员将不得不为每个单独的成员函数重复调用此函数。无论如何使用预处理器或任何预处理库(如boost-wave),以便程序员不必进行这些重复调用?
编辑: 对不起,我很清楚这里没有充分描述这个问题。 我将字符串映射到成员函数指针;
m_urlRules是一个std :: map,其中string为键,成员函数指针为value regController基本上是m_urlRules的setter函数,因此两个语句有效地做同样的事情,它将字符串映射到成员函数。
REG_NAME是一个取代非常难看的类型转换的宏。
我要做的是,如果类具有以下结构,
class DerivedController : public BS_Controllers
{
public:
DerivedController():BS_Controllers(this);
void * print();
void * print2();
void * print3();
void * print4();
};
我不必在构造函数中执行以下操作:
m_urlRules["print"] = REG_NAME &DerivedController::print;
m_urlRules["print1"] = REG_NAME &DerivedController::print1;
m_urlRules["print2"] = REG_NAME &DerivedController::print2;
m_urlRules["print3"] = REG_NAME &DerivedController::print3;
m_urlRules["print4"] = REG_NAME &DerivedController::print4;
答案 0 :(得分:0)
我不完全确定我完全理解你的问题,但为什么不使用内置的数据结构,例如map,你可以将它映射到一个键(你的字符串)。
答案 1 :(得分:0)
我认为您希望将此功能用于记录原因,以查看问题出现的位置。
我认为你正在寻找类似的东西:
urlRules ("<function name>");
regController("<function name>");
而不是
m_urlRules["<function name>"] = REG_NAME &DerivedController::print;
regController(REG_NAME &DerivedController::printView,"<function name>");
您可以像这样定义这样的makros:
#define urlRules(x) { m_urlRules[(x)] = REG_NAME &DerivedController::print; }
#define regController(x) { regController(REG_NAME &DerivedController::printView,(x)); }
注意:我没有测试它,它可能不起作用,但在我的理解中它应该。
修改强>:
现在我明白了,你想要在构造函数中调用每个函数。 实际上,构造函数是错误的,因为它为你创建的每个对象调用,但你只需要指定一次。 (例如在启动时)
请参阅,类的函数只在内存中存在一次,并且连接到指针的东西是yield数据,因此所有成员变量都是。
没有简单的方法可以通过名称获取所有类成员,然后对其进行操作,抱歉。 至少不是我所知道的。
但是你应该记住,对于任何给定的对象,函数指针都不会改变。 执行工作的外部功能将更加智能化。在启动时调用。
答案 2 :(得分:0)
好吧,您正在尝试自己构建运行时类型信息(RTTI),因此没有预处理器宏。主要是因为预处理器宏扩展到一个地方,并且您声明的位置和注册函数的位置是不同的。
Qt和qmake,做这样的事情,它找到标记信号/槽的函数,并为RTTI构建一个moc对象。这是关于使用c ++可以获得的最佳效果。其他语言(如java和delphi)比c ++具有更多的RTTI,并且可以在运行时查询函数。
答案 3 :(得分:0)
我首先要删除丑陋的类型转换(即使是宏形式)。这可以通过将m_urlRules
移出BS_Controllers
并进入中间(或代理)模板类来完成。该模板用于将地图解析为正确的派生类型。 (我不知道你如何定义BS_Controllers
,所以我做了一个。)
class BS_Controllers {
protected:
virtual ~BS_Controllers () {}
public:
virtual void * invokeRule (const std::string &) = 0;
};
template <typename D>
class BS_Proxy : public BS_Controllers {
typedef std::map<std::string, void *(D::*)()> UrlRuleMap;
static UrlRuleMap & urlRules () {
static UrlRuleMap urlRules_;
return urlRules_;
}
void * invokeRule (const std::string &s) {
typename UrlRuleMap::iterator i = urlRules().find(s);
if (i == urlRules().end()) return 0;
return (dynamic_cast<D *>(this)->*(i->second))();
}
protected:
static void regController (void *(D::*m)(), const std::string &s) {
urlRules()[s] = m;
}
};
现在,通过调用代理类的DerivedController
方法,可以非常轻松地初始化regController
。
#define REG_RULE(D, x) BS_Proxy<D>::regController(&D::x, #x)
class DerivedController : public BS_Proxy<DerivedController> {
struct Populate {
Populate () {
REG_RULE(DerivedController, print);
REG_RULE(DerivedController, printView);
}
};
public:
DerivedController() {
static Populate populate_;
}
void * print() { return NULL; }
void * printView() {
std::cout<<"Print view!"<<std::endl;
return NULL;
}
};
您可以查看上述代码的demo。
如果要使群体半自动,您仍然需要定义某处方法的列表。您可以将它们列在文件中。
// DerivedController rules
DERIVED_RULE_INC(print)
DERIVED_RULE_INC(printView)
//...
然后更改您的DerivedController
课程以使用此文件:
class DerivedController : public BS_Proxy<DerivedController> {
struct Populate {
Populate () {
#define DERIVED_RULE_INC(x) REG_RULE(DerivedController, x);
#include "derived_controller_rules.inc"
#undef DERIVED_RULE_INC
}
};
public:
DerivedController() {
static Populate populate_;
}
#define DERIVED_RULE_INC(x) void * x ();
#include "derived_controller_rules.inc"
#undef DERIVED_RULE_INC
};
void * DerivedController::print() { return NULL; }
void * DerivedController::printView() {
std::cout<<"Print view!"<<std::endl;
return NULL;
}
现在,如果您向该文件添加其他规则,则注册代码和方法声明是自动的。但是需要实现该方法的定义,否则将生成关于缺少的方法定义的链接器错误。