IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

map de méthodes dans la classe


Sujet :

C++

  1. #1
    Nouveau Candidat au Club
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2014
    Messages : 3
    Points : 1
    Points
    1
    Par défaut map de méthodes dans la classe
    ...ou comment appeler des méthodes par une string, au sein de la clasee.

    Bonjour,

    Est-il possible d'avoir dans la même classe un map de string vers des méthodes de la classe ?

    La motivation: dans une classe Config, j'implémente une méthode read(), qui parse un fichier de config, et qui, pour chaque mot-clef, appelle une fonction parseConsume(key, val). Dans parseConsume(), je peux faire des else if (key == "clef1"), mais il me paraissait plus élégant de faire ParseMap::const_iterator iter = parseHandler.find(key), puis (*this.*(iter->second))(val) (ou approchant) où parseHandler serait initialisé dans le constructeur à base de:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    parseHandle["key1"] = &key1Def;
    et serait défini ainsi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    typedef void (Config::* ParseFunc)(std::string);
    typedef std::map<std::string, ParseFunc> ParseMap;
     
    class Config
    {
    // ...
    private:
      ParseMap parseHandler;
    // ...
    MAIS

    au vu des erreurs du compilo, il semble que ce soit plus compliqué, voire impossible. J'ai cru comprendre qu'il faudrait éventuellement utiliser un delegate. Mais bon si on en arrive là, je préfère rester avec mes else if.

    Qu'en pensez-vous ?





  2. #2
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Je trouve le fait d'utiliser une map pour faire cela tres elegant. Cependant il faudra que tu ajoutes "a la main" les fonctions a appeler selon la "cle" donnee (dans ton constructeur ce sera parfait). Ce topic en parlait plutot bien je trouvais, tu devrais y jeter un coup d'oeil.

    A part ca je ne vois pas d'ou vient l'erreur, pourrais-tu nous montrer les messages du compilo s'il-te-plait ?

  3. #3
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    La syntaxe des appels vers des fonctions membres via des pointeurs est obscure et très sujette à erreur.

    Je te conseille la lecture de ceci :
    http://www.parashift.com/c++-faq-lit...-to-memfn.html

    et de bien appliquer les conseils qui y sont donnés pour éviter les erreurs.

    Normalement, ce que tu décris devrait marcher.

  4. #4
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Utilise std::function et std::mem_fn, ce sera plus facile à manipuler qu'un pointeur vers une fonction membre. Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <iostream>
    #include <functional>
    #include <map>
     
    class Config {
      using parse_mem_fn = std::function<void(Config&, std::string const&)>;
      std::map<std::string, parse_mem_fn> handlers_;
     
     public:
      Config() {
        handlers_["key1"] = std::mem_fn(&Config::consumeKey1);
      }
     
      void consumeKey1(std::string const& value) {
        std::cout << "Yay ! " << value << std::endl;
      }
     
      void parseConsume(std::string const& key, std::string const& value) {
        parse_mem_fn & func = handlers_[key];
        if (func) func(*this,value);
      }
     
      void parse() {
        parseConsume("key1","test");
      }
    };
     
    int main() {
      Config c;
      c.parse();
      return 0;
    }
    Tu peux aussi tester avec un unordered_map pour voir si ça te fais de meilleures perfs.

    Edit:

    Je viens de penser à une syntax sympa qui permet d'initialiser handlers_ de manière plus naturelle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <iostream>
    #include <functional>
    #include <map>
     
    class Config {
      using parse_mem_fn = std::function<void(Config&, std::string const&)>;
      std::map<std::string, parse_mem_fn> handlers_ {{ 
        {"key1", std::mem_fn(&Config::consumeKey1)}
        ,{"key2", std::mem_fn(&Config::consumeKey2)}
      }};
     
     public:
      void consumeKey1(std::string const& value) { std::cout << "Yay ! " << value << std::endl; }
      void consumeKey2(std::string const& value) { std::cout << "Ole ! " << value << std::endl; }
     
      void parseConsume(std::string const& key, std::string const& value) {
        parse_mem_fn & func = handlers_[key];
        if (func) func(*this,value);
      }
     
      void parse() {
        parseConsume("key1","test");
        parseConsume("key2","test");
      }
    };
     
    int main() {
      Config c;
      c.parse();
      return 0;
    }
    Find me on github

  5. #5
    Nouveau Candidat au Club
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Juin 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Juin 2014
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Z'êtes trop forts! En fait, mon problème était que je n'avais pas pensé à soit déclarer les typedef dans la classe, soit forward-déclarer la classe avant les typedef.
    Merci à tous pour vos réponses éclairées. Merci à jblecanard pour la version c++11!

Discussions similaires

  1. [Composite] Méthode dans la classe Abstraite Component
    Par didine6393 dans le forum Design Patterns
    Réponses: 4
    Dernier message: 09/09/2009, 14h28
  2. placer une méthode dans une classe
    Par totoche dans le forum UML
    Réponses: 8
    Dernier message: 29/05/2008, 17h04
  3. Importation de méthodes dans une classe
    Par jarboo dans le forum C#
    Réponses: 1
    Dernier message: 25/07/2007, 12h21
  4. Ajout d'une méthode dans une classe
    Par Flow_75 dans le forum C++
    Réponses: 6
    Dernier message: 12/02/2007, 10h42
  5. Réponses: 4
    Dernier message: 25/05/2006, 14h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo