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 :

Pointeur de fonctions membres


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Par défaut Pointeur de fonctions membres
    Bonjour à tous,

    J'ai un problème de conception que je n'arrive pas à résoudre.

    J'aimerais créer un objet qui puisse appeler les méthodes d'autres objets.
    C'est dans le cadre d'une console graphique. J'aimerais avoir l'objet "Console" d'un coté, et depuis l'objet, disons "Ecran" binder la méthode "resize" depuis la classe "Ecran" à ma console.
    Et qu'ensuite avec la console, appeler un objet de type "Ecran" et sa méthode "resize" quand je tape une commande que j'aurais définie pendant le bind.

    Seulement, je n'arrive pas à stocker des pointeurs de fonctions membres dans un containeur, parce qu'évidemment le type diffère.
    Et je n'y arrive pas non plus avec les templates. Le compilateur m'oblige à faire un containeur par type.

    Est ce que quelqu'un à une idée ? Il n'y aurait que le nom de la classe qui diffère.
    Je vais forcer le prototype à "std::string fonction (const std::string & param)", ça suffira amplement.

    J'ai déjà tenté le tutorial de Laurent Gomila, mais j'ai pleins d'erreurs à la compilation dû aux templates et à des appels de méthode virtuelle non définie.
    Il y a un peu trop d'étapes, alors je ne sais pas par où commencer pour comprendre les problèmes de compilation.
    Je suis avec GCC(-std=c++0x) sous linux. C'est peut-être pour ça que j'ai un tas de bugs avec les templates.
    J'ai l'habitude d'instancier mes templates dans un fichier spécial. Ici je vois pas quoi instancier... Autant être franc, je comprend rien lol.

    NOTE : je me suis planté de forum, il y a moyen qu'un modérateur me le déplace dans le forum général C++. Merci.

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    D'après les informations que tu donnes, je ne vois pas l'intérêt d'utiliser des pointeurs sur fonctions membres. Si tu veux définir des associations entre des mots-clefs et des appels de méthode, pourquoi ne pas tout simplement créer des objets commande capable d'une part de reconnaître un mot-clef, et d'autre part d'appeler une méthode sur une référence à laquelle ils sont liés à l'instanciation. Ce que tu demandes ressemble à de la réflexion sur fonction, mais je ne crois pas que C++ sache faire ça...donc tu devras de toutes façons le coder d'une manière ou d'une autre.

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Par défaut
    J'ai essayé avec des objets fonctions.

    J'ai un objet générique pour la commande.
    Ensuite pour chaque classe à laquelle je souhaite lier des commandes en console, j'ai un objet commande enfant (J'ai fait ça avec des templates).

    Ensuite, dans ma console, je peux faire un vecteur d'objets commandes génériques.
    Simplement j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    commandGeneric * newCmd = new commandSpecific(monObjetParticulier, &monObjetParticulier::laMethodeQuiVaAvec);
     
    m_mesCommandes.push_back( newCmd );
    Ensuite, C++ ne m'interdit pas en partant de l'objet parent d'utiliser les commandes enfants. En faisant de la surcharge d'opérateur () au niveau du parent une méthode virtuelle pure (Comme ça je suis sûr que le compilateur criera s'il utilise la version du parent).
    Je ne sais pas si c'est bien, mais ça fait plus ou moins ce que j'aimerais. Maintenant, je trouve ça un peu bizarre, je comprends pas comment ça peut marcher.

    Pour la destruction des objets alloués pour les commandes, c'est la console qui s'occupe de parcourir tout le vecteur à sa destruction en détruisant chaque commande.

  4. #4
    Membre Expert
    Homme Profil pro
    Inscrit en
    Décembre 2010
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 734
    Par défaut
    comment ça marche? Tu as fait ce qu'on appelle un type erasure: une classe mère non-template avec une interface commune qui permet d'utiliser les classes dérivées templatisées "comme des" commande génériques (principe fondamental pour utiliser l'héritage.
    Si ça répond à ton problème c'est OK!
    Par curiosité, comment fais-tu la reconnaissance mot-clef->commande?

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Septembre 2009
    Messages : 70
    Par défaut
    D'accord, on peut dire que c'est une interface en POO ?

    Pour la reconnaissance, c'est vrai qu'avec un vecteur c'est un peu weird , mais j'ai volontairement simplifier le code ici pour ne pas parasiter ma question. Sinon j'utilise un container map.

    L'objet fonction générique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class Functor
    {
    	public:
    		/* === Public constructors & destructor === */
     
    		Functor (void);
    		virtual ~Functor (void);
     
    		/* === Operator overloading === */
     
    		virtual std::string operator() (const std::string & parameters) const = 0;
    };
    L'objet fonction spécifique :

    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
     
    template < typename classType >
    class ClassFunctor : public Functor
    {
    	private:
    		/* === Private members === */
     
    		classType * m_object;
    		std::string (classType::* m_methodPtr)(const char *);
     
    		/* === Private constructors & destructor === */
     
    		ClassFunctor (classType * object, std::string (classType::* methodPtr)(const char *));
    		~ClassFunctor (void);
     
    	public:
     
    		/* === Public operator overloading === */
     
    		std::string operator() (const std::string & parameters) const;
     
    		/* === Public processing methods === */
     
    		static Functor * createFunctor (classType * object, std::string (classType::* methodPtr)(const char *));
    };
    Le collectionneur de commandes :

    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
     
    class Manager : public Singleton< Manager >
    {
    	friend class Singleton< Manager >;
     
    	private:
    		/* === Private typedef === */
     
    		typedef std::map< std::string, Functor * > FunctorsMap;
    		typedef std::pair< std::string, Functor * > FunctorsMapElement;
     
    		/* === Private members === */
     
    		FunctorsMap m_commands;
     
    	public:
    		/* === Public constructors & destructor === */
     
    		Manager (void);
    		~Manager (void);
     
    		/* === Public processing methods === */
     
    		void bindCommand (const std::string & funcName, Functor * function);
    		bool unbindCommand (const std::string & funcName);
     
    		void execute (const std::string & rawCommand) const;
    };
    Ensuite dans un objet où je veux lier une de ses méthodes à une commande console, je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    m_scriptsManager->bindCommand("version", Scripts::ClassFunctor< Core >::createFunctor(this, &Core::version));
    m_scriptsManager->bindCommand("exit", Scripts::ClassFunctor< Core >::createFunctor(this, &Core::shutdown));
    Voila. S'il y a des trucs qui frappent, les critiques sont les bienvenues.

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Ce code est déjà d'un bon niveau

    Je me permets quelques remarques :
    => maintenant que tu sais comment on implémente Functor et ClassFunctor, tu peux utiliser leur version éprouvée : std::bind et std::function <std::string (std::string const&)> si tu as un compilateur C++11 (Visual 10 ou gcc > 4.??) ou sinon utilises les Boost.Bind et Boost.Function

    => si d'aventure tu ne v/peux pas utiliser ces bibliothèques, je te conseille le pimpl idiom pour redonner à Functor une sémantique de valeur ce qui me semble plus cohérent. Cela permettrait de le stocker par valeur dans ton conteneur. Sans oublier un smart pointer. Ce qui pourrait ressembler à
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    namespace
    {
       class FunctorImpl
       {
    // grosso modo ton ancien Functor
       };
     
     
       template < typename classType >
       class ClassFunctorImpl : public FunctorImpl
       {
    // grosso modo ton ancien ClassFunctor
       };
    }
     
    class Functor
    {
    public:
       std::string operator() (const std::string & parameters) const
       {
          return (*p_impl)(parameters);
       }
    private:
       std::unique_ptr<FunctorImpl> p_impl;
    };
     
    // ce qui permet de se passer de pointeurs : 
     
    class Manager : public Singleton< Manager >
    {
    	friend class Singleton< Manager >;
     
    	private:
    		/* === Private typedef === */
     
    		typedef std::map< std::string, Functor > FunctorsMap;
    		typedef std::pair< std::string, Functor > FunctorsMapElement;
     
    		/* === Private members === */
     
    		FunctorsMap m_commands;
     
    	public:
    		/* === Public constructors & destructor === */
     
    		Manager (void);
    		~Manager (void);
     
    		/* === Public processing methods === */
     
    		void bindCommand (const std::string & funcName, Functor const& function);
    		bool unbindCommand (const std::string & funcName);
     
    		void execute (const std::string & rawCommand) const;
    };
    => Je ne sais pas comment tu as écrit ta classe singleton mais manager devrait avoir son constructeur et son destructeur en privé.

    => Sur les classes manager : De la gestion des gestionnaires

    => Sur les singletons : Etes-vous atteint de Singletonite ?. Singletons, monostate et autres variables globales, cf ici.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Pointeur sur fonction membre avec parametre
    Par Glosialabolas dans le forum C++
    Réponses: 7
    Dernier message: 06/02/2006, 02h32
  2. Pointeur de fonction membre.
    Par fabone dans le forum C++
    Réponses: 2
    Dernier message: 18/01/2006, 13h18
  3. Pointeur de fonction membre
    Par legend666 dans le forum C++
    Réponses: 1
    Dernier message: 04/10/2005, 20h46
  4. Réponses: 10
    Dernier message: 03/02/2005, 13h09
  5. Réponses: 5
    Dernier message: 12/01/2005, 20h58

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