2009-03-10 6 views
8

Je souhaite mapper une chaîne à une fonction de membre d'instance et stocker chaque mappage dans la carte.Stockez des pointeurs vers la fonction de membre dans la carte

Quelle est la façon propre de faire quelque chose comme ça? Laissez-moi savoir si vous voyez un problème avec cette approche et quels sont les idiomes communs pour cela?

Peut-être, je devrais utiliser si-else, si la chaîne de déclaration, étant donné que j'ai un nombre limité de fonctions membres, au lieu d'une carte confusion des pointeurs func

BTW, je l'ai trouvé un peu de l'utile infos ici dans le c++-faq-lite

+0

En fait, je pense que la carte est plus agréable que si une chaîne-else. Il vous donne un bon crochet pour stocker d'autres méta-informations plus tard si le besoin s'en fait sentir - il suffit d'étendre le type de valeur du pointeur de fonction à une structure contenant un pointeur de fonction plus toutes les autres informations dont vous avez besoin. –

+0

Je suis d'accord, a l'air mieux, mais plus difficile à comprendre pour un développeur moins expérimenté. –

Répondre

6

Attend bien pour moi, mais pour le fait que descrToFuncMap doit être déclarée static si vous avez l'intention de l'initialiser à l'intérieur de la fonction statique Initialize().

Si vous voulez vous assurer que Initialize() est appelé, et qu'il est appelé une seule fois, vous pouvez utiliser le motif Singleton. Fondamentalement, si vous ne faites pas le multithreading, cela signifie juste l'emballage descrToFuncMap à l'intérieur de sa propre classe (appelée par exemple FuncMap) avec un constructeur privé qui appelle Initialize(). Ensuite, vous ajoutez une variable locale static de type FuncMap à Processor::Process() - car la variable est static, elle persiste et n'est initialisée qu'une seule fois.

Exemple code (je me rends compte maintenant que friend est pas vraiment nécessaire ici):

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

Ce n'est pas le « vrai » modèle Singleton comme des fonctions différentes peuvent créer leurs propres instances distinctes de FuncMap, mais c'est assez pour ce dont tu as besoin. Pour "true" Singleton, vous devez déclarer le constructeur FuncMap privé et ajouter une méthode statique, par exemple getInstance(), qui a défini l'instance unique comme une variable static et renvoyé une référence à cela. Processor::Process() serait alors l'utiliser avec

FuncMap& fm = FuncMap::getInstance(); 
+0

Oui, il est statique (le fixe). J'aime l'idée d'une classe d'amis privés. Voulez-vous le démontrer avec un exemple? Merci –

0

Je changerais

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

à

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

Ne voyez aucun mauvais effet secondaire pour le moment. Probablement avec boost :: function comme une valeur de carte, il sera plus facile dans le futur.

+0

bien oui, évidemment je passerais la chaîne comme un const à la référence. Ma question est peut-être, je devrais utiliser la chaîne if-statement étant donné que j'ai un nombre limité de fonctions membres au lieu d'une carte confuse des pointeurs func –

+0

Les cartes sont ok pour moi. –

0

Évitez d'utiliser « virtuel » si vous utilisez des cartes de pointeurs de fonction. Dans ce contexte, l'utilisation d'un mot clé «virtuel» n'aidera pas beaucoup. Par exemple

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

appellera toujours 'MyClass :: GetX', même si la fonction GetX est remplacée par la classe dérivée de MyClass.

Habituellement, vous n'aurez pas un grand nombre de fonctions en classe, plutôt que d'utiliser map, vous pouvez créer un simple tableau struct et utiliser une boucle for.Si le nombre de fonctions est petit, il n'y aura pas de grande différence de performance dans la carte et le tableau. Quelque chose de semblable au code ci-dessous fonctionnera

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; 
     } 
    }  
} 
+0

Pourquoi n'appelle-t-il pas une fonction surchargée? –

Questions connexes