将指针存储在地图中的成员函数中

时间:2009-03-10 15:57:15

标签: c++ design-patterns callback

我想将字符串映射到实例成员函数,并将每个映射存储在映射中。

做这样的事情的干净方法是什么?

class  MyClass
{
   //........
   virtual double GetX();
   virtual double GetSomethingElse();
   virtual double GetT();
   virtual double GetRR();
   //........
};


class Processor
{
 private:
      typedef double (MyClass::*MemFuncGetter)();
      static map<std::string, MemFuncGetter> descrToFuncMap;

 public:
        static void Initialize();
        void Process(Myclass m, string);
};

void Processor::Initialize()
{

     descrToFuncMap["X"]=&MyClass::GetX;
     descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
     descrToFuncMap["RR"]=&MyClass::GetRR;
     descrToFuncMap["T"]=&MyClass::GetT;
};
void Processor::Process(MyClass ms, const std::string& key)
{
     map<std::string, Getter>::iterator found=descrToFuncMap.find(key);
     if(found!=descrToFuncMap.end())
     {
        MemFuncGetter memFunc=found->second;
        double dResult=(ms).*memFunc();    
        std::cout<<"Command="<<key<<", and result="<<result<<std::end;      
      }
 }  

如果你发现这种方法存在问题并且常见的习惯用法是什么,请告诉我们?

也许,我应该使用if-else-if语句链,因为我的成员函数数量有限,而不是令人困惑的func指针映射

顺便说一句,我在c++-faq-lite

中找到了一些有用的信息

3 个答案:

答案 0 :(得分:6)

对我来说很好,但是如果你打算从静态函数descrToFuncMap内部初始化它,那么static需要声明Initialize()

如果要确保调用Initialize(),并且只调用一次,则可以使用Singleton模式。基本上,如果您没有进行多线程处理,那只意味着将descrToFuncMap包装在其自己的类(称为FuncMap)中,并使用调用Initialize()的私有构造函数。然后,您将static类型FuncMap的{​​{1}}局部变量添加到Processor::Process() - 因为变量为static,它会持续存在并且只会初始化一次。

示例代码(我现在意识到friend在这里并不是必需的):

class Processor {
private:
    typedef double (MyClass::*MemFuncGetter)();

    class FuncMap {
    public:
        FuncMap() {
            descrToFuncMap["X"]=&MyClass::GetX;
            descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse;
            descrToFuncMap["RR"]=&MyClass::GetRR;
            descrToFuncMap["T"]=&MyClass::GetT;
        }

        // Of course you could encapsulate this, but its hardly worth
        // the bother since the whole class is private anyway.
        map<std::string, MemFuncGetter> descrToFuncMap;
    };

public:
    void Process(Myclass m, string);
};

void Processor::Process(MyClass ms, const std::string& key) {
    static FuncMap fm;      // Only gets initialised on first call
    map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key);
    if(found!=fm.descrToFuncMap.end()) {
        MemFuncGetter memFunc=found->second;
        double dResult=(ms).*memFunc();    
        std::cout<<"Command="<<key<<", and result="<<result<<std::end;      
    }
}

这不是“真正的”Singleton模式,因为不同的函数可以创建自己独立的FuncMap实例,但它足以满足您的需求。对于“true”Singleton,您可以将FuncMap的构造函数声明为private并添加一个静态方法,比如getInstance(),它将唯一实例定义为static变量并返回对此的参考。然后Processor::Process()会将其与

一起使用
FuncMap& fm = FuncMap::getInstance();

答案 1 :(得分:0)

我要改变

void Processor::Process(MyClass ms, std::string key)

void Processor::Process(const MyClass& ms, const std::string& key)

目前看不出任何不良副作用。可能使用boost :: function作为地图值,将来会更容易。

答案 2 :(得分:0)

如果使用函数指针的映射,请避免使用'virtual'。在这种情况下,使用'virtual'关键字无济于事。例如

descrToFuncMap["X"]=&MyClass::GetX;

将始终调用' MyClass :: GetX '函数,即使 GetX 被MyClass的派生类覆盖。

通常你不会在类中拥有大量的函数,而不是使用map你可以创建简单的struct数组并使用for循环。如果函数的数量很少,则地图和数组中的性能差异不会很大。类似于下面的代码的东西将起作用

class  MyClass
{
   //........
   double GetX();
   double GetSomethingElse();
   double GetT();
   double GetRR();
   //........
};

typedef double (MyClass::*MemFuncGetter)();

struct FuncTable
{
    const char* m_pFuncName;
    MemFuncGetter m_pFuncPtr;
};

class Processor
{          
 public:
        void Process(Myclass& m, string);
};

static FuncTable descrToFuncMap[]
{
    { "X",  &MyClass::GetX},
    { "SomethingElse", &MyClass::GetSomethingElse },
    { "RR", &MyClass::GetRR},
    { "T", &MyClass::GetT}
};

void Processor::Process(MyClass& ms, const std::string& key)
{
    int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0])

    for(int i=0; i< functablesize; ++i)
    {   
        if( strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0)
        {
            MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr;
            double dResult=(ms).*memFunc();    
            std::cout<<"Command="<<key<<"result="<<result<<std::end;
            break;
        }
    }     
 }