1

我有一个非常简单的类定义如下:

#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,以字符串为键,成员函数指针为值 regController 基本上是 m_urlRules 的设置器函数,因此这两个语句有效地执行相同的操作,将字符串映射到成员函数。

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;
4

4 回答 4

0

我相信您出于日志记录的原因想使用此功能,以查看问题出现在哪里。

我认为您正在寻找类似的东西:

urlRules     ("<function name>");
regController("<function name>");

代替

m_urlRules["<function name>"] = REG_NAME &DerivedController::print;
regController(REG_NAME &DerivedController::printView,"<function name>");

你可以像这样定义这样的宏:

#define      urlRules(x) { m_urlRules[(x)] = REG_NAME &DerivedController::print; }
#define regController(x) { regController(REG_NAME &DerivedController::printView,(x)); }

注意:我没有测试过,它可能不起作用,但据我了解应该。

编辑

啊,现在我明白了,您想要调用构造函数中的每个函数。实际上,构造函数是错误的地方,因为它会为您创建的每个对象调用,但您只需分配 this 指针一次。(例如在启动时)

看,一个类的函数在内存中只存在一次,与指针相连的就是yield数据,所以所有的成员变量。

抱歉,没有简单的方法可以按名称获取所有类成员然后遍历它们。至少不是我所知道的。

但是您应该记住,函数指针不会因任何给定对象而改变。做这项工作的外部功能会更智能。启动时调用。

于 2012-08-11T02:08:50.193 回答
0

我不确定我是否完全理解您的问题,但为什么不使用内置数据结构,例如 map,您可以在其中将其映射到一个键(您的字符串)。

这里有一些例子

于 2012-08-11T01:56:56.990 回答
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;
    }
};

您可以查看上述代码的演示。

如果您想使填充半自动,您仍然必须在某处定义方法列表。您可以在文件中列出它们。

// 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;
}

现在,如果您在文件中添加另一个规则,注册码和方法声明是自动的。但是需要实现方法的定义,否则会产生关于缺少方法定义的链接器错误。

于 2012-08-11T09:52:11.627 回答
0

好吧,您正在尝试自己构建运行时类型信息 (RTTI),因此没有预处理器宏。主要是因为预处理器宏扩展到一个地方,而你声明的地方和注册你的函数的地方是不同的。

Qt 和 qmake 做了类似的事情,它找到标记为信号/插槽的函数,并为 RTTI 构建一个 moc 对象。这大约是您可以使用 c++ 获得的最佳效果。其他语言,如 java 和 delphi,比 c++ 具有更多的 RTTI,并且可以在运行时查询函数。

于 2012-08-11T02:12:40.993 回答