试图避免重复调用函数

时间:2012-08-11 01:33:18

标签: c++ member-function-pointers boost-preprocessor

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

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

4 个答案:

答案 0 :(得分:0)

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

Here some examples

答案 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;
}

现在,如果您向该文件添加其他规则,则注册代码和方法声明是自动的。但是需要实现该方法的定义,否则将生成关于缺少的方法定义的链接器错误。