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

Langage C++ Discussion :

Pointeur de fonction et template ?


Sujet :

Langage C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Août 2004
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2004
    Messages : 152
    Points : 70
    Points
    70
    Par défaut Pointeur de fonction et template ?
    Bonjour à tous,

    Je programme en ce moment un petit jeu et j'ai un petit soucis qui me dépasse pas mal. Je dois faire quelque chose d'abstrait et vu que je vais peut-être devoir utiliser les template je préfère demander à la communauté si c'est la meilleure solution pour mon problème.

    Et bien voilà, j'ai des classes enfants (machine, soldats, etc...) qui dérivent toute d'une classe abstraite "entitée". Ces classes enfants ont des fonctions pour faire des actions comme tirer, appliquer des effets, dégats etc...

    Maintenant pour gérer le temps, sans rentrer dans les détails j'ai fais un début de classe (TimedAction) pour gérer quand une fonction doit intervenir selon un intervalle. Attention voici la question super précise :
    J'aurai besoin d'un pointeur d'une méthode d'une classe enfant ( ex: soldat->tirer() ) pour pouvoir l'appeller AVEC un ou des paramètres ( ex: soldat->tirer(5, 15) ) donnés en paramètre lors de la création de la classe TimedAction. En gros cela ressemblerai à ce pseudo-code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Soldat* soldatA = new Soldat("Soldat");
    // toutes les 1 secondes, appeler tirer() de la classe Soldat avec les paramètres 5, 15, etc... (par ex: 5=dégats ; 15=vitesse ;...) :
    TimedAction* timeSoldatATirer< Soldat > = new TimedAction(1, *soldatA->tirer(), 5, 15, ...);
    // Serait pareil que faire soldatA->tirer(5, 15, ...) :
    timeSoldatATirer->execute();
    Pour résoudre ce problème j'ai pensé stoquer dans la classe TimedAction une variable pointeur de l' "Entité" (Entity*), mais alors la fonction tirer() ne fait pas partie de cette classe abstraite (Entity) et va donner une erreure si je ne me trompe ? Il faudrait aussi éviter les virtual puisque n'importe quels méthodes devra être spécifiée comme recharger() en paramètre à la création d'une instance TimedAction.
    Dans ce cas il faut envoyer le type de classe (Soldat ici) directement pour appeller la méthode? j'ai pensé aux templates qui utilise le type de classe donné. Je n'ai jamais utilisé ceci donc je ne sais pas vraiment comment transformer TimedAction en template. De plus est-ce la meilleur solution, la plus lisible, propre ?
    Ensuite comment faire pour envoyer un nombre N de paramètres à la fonction quand on fait le prototype de celle-ci ou pour l'appeler par TimedAction ? Je pensais simplifier en mettant tous les paramètres dans un vector mais c'est peut-être pas la meilleur solution non plus.

    Merci d'avance !

    EDIT: Pour le moment j'ai un pseudo-code qui ressemble à ça pour TimedAction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    template < typename T > class TimedAction {
    	public:
    		TimedAction();
    		~TimedAction();
     
    	private:
    		unsigned int actionRAInterval;
    		T *actionObject; // Not necessary when the function pointer contains the object directly
    		// unknow type of variable // Arguments to give with the function to cast
    		bool (T::functionName)(functionParameter1, functionParameterN); // Prototype of the pointer on the function to cast
    		unsigned int lastActionRACast;
    		bool continueCastingAfter;
    };

  2. #2
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Bonsoir,
    Je crois que la solution la plus simple serai d'utiliser la class boost::function, avec le boost::bind. Ainsi tu n'as plus besoin de fair un TimedAction template:

    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
     
    class TimedAction
    {
      typedef boost::function<void(void)> FuncType;
      unsigned int actionRAInterval;
      FuncType function_;
     
    public:
      TimedAction(int interv, FuncType func):
        actionRAInterval(interv),
        function(func)
      {
      }
     
      void excecute()
      {
        function_();
      }
    };
     
    Soldat* soldatA = new Soldat("Soldat");
    // toutes les 1 secondes, appeler tirer() de la classe Soldat avec les paramètres 5, 15, etc... (par ex: 5=dégats ; 15=vitesse ;...) :
    TimedAction* timeSoldatATirer = new TimedAction( 1, boost::bind(&Soldat::tirer, soldatA , 5, 15));
    // Serait pareil que faire soldatA->tirer(5, 15, ...) :
    timeSoldatATirer->execute();

  3. #3
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    La question, bien que technique, est plus du domaine de la conception.
    Je ne peux que t'inviter à regarder ce sujet qui est au final très proche du tient et de constater que les réponses vont dans le même sens sur les deux sujets (boost::fonction + boost::bind et/ou boost::any/variant avec des structures pour passer les paramètres)

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Août 2004
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2004
    Messages : 152
    Points : 70
    Points
    70
    Par défaut
    Merci énormément à vous deux, n'ayant jamais utilisé la librairie Boost j'ai dû me renseigner un peu plus avant d'utiliser le code. J'ai écrit la partie de ma classse c'est propre et simple mais il me reste un dernier soucis. J'aimerai que la fonction bindée quand elle est appelée puisse avoir un pointeur sur l'instance TimedAction qui l'a appelée. Ca me permettrait de modifier ses variables (à travers des guetteurs bien sûr), changer la fréquence d'appel et pourquoi pas changer la fonction appelée, etc...

    J'ai pensé rajouter en premier, un argument pointeur this dans la méthode doAction() avant d'appeler la fonction. (Comme je l'ai dis je découvre Boost je n'ai pas trouvé sur le site la doc officielle de Boost::Bind ! Donc je ne sais pas s'il est possible d'ajouter des arguments après avoir fait l'object Bind.)
    Sinon je peux toujours stoquer un pointeur sur l'instance de TimedAction qui devrait être créer dans une entité dont la classe est appellée par TimedAction justement mais c'est moins propre je trouve. Surtout parce que je ne pourrais pas créer un TimedAction n'importe où alors. Donc à oublier !

    Je ne sais pas si j'ai été clair mais je souhaite que la fonction bindée puisse appeler des méthode de l'instance de TimedAction qui l'a castée. Sinon voilà mon code actuelle (raccourci) :
    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
    class TimedAction {
    	typedef boost::function< void(void) > castingFunctionType;
     
    	public:
    		TimedAction(unsigned int _actionRAInterval, castingFunctionType _actionFunction, bool _continueCastingAfter = true, unsigned int _lastActionRACast = 0);
    		~TimedAction();
    		bool doAction();
     
    	private:
    		unsigned int actionRAInterval;
    		castingFunctionType actionFunction;
    		bool continueCastingAfter;
    		unsigned int lastActionRACast;
    };
    // constructor method
    TimedAction::TimedAction(unsigned int _actionRAInterval, castingFunctionType _actionFunction, bool _continueCastingAfter, unsigned int _lastActionRACast);
    : actionRAInterval(_actionRAInterval), actionFunction(_actionFunction), continueCastingAfter(_continueCastingAfter), lastActionRACast(_lastActionRACast) {
     
    }
     
    // destructor method
    TimedAction::~TimedAction() {
     
    }
     
    // Cast the bound function with parameters
    bool TimedAction::doAction() {
    	/* Rajouter un pointeur this en premier argument à l'appel ci-dessous ? */
    	return actionFunction(); /* La fonction devra retourner un bool pour savoir si tout s'est bien passé */
    }
    Un peu à part, j'aurais voulu savoir comment faire des fonctions avec un nombre de paramètres indéterminés un peu comme Boost::Bind justement, ça peut toujours servir.

    Merci de votre coup de main !

  5. #5
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Si j'ai bien compris, tu as une fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bool Soldat::tirer(int, int, TimedAction*);
    Et tu voudrai la binder en définissant les int, mais pas le TimedAction, et ne le définir qu'a l'appel final?

    Si c'est bien ca alors fait le bind comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::bind(&Soldat::tirer, soldatA , 5, 15, _1)
    En gros ça signifie que tu défini les deux premier paramétres mais pas le troisième, et qu'il sera placé en premier argument(il n'y en as plus q'un de toute façon).

    Du coup il faut changer ton typedef pour:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef boost::function< bool(TimedAction*) > castingFunctionType;
    Ainsi tu pourra fait l'appel comme tu le souhaite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    return actionFunction(this);
    J'avais aussi eu du mal avec ça la première fois que je me suis plongé dans boost::bind.

    Pour ce qui est des fonctions avec un nombre indéterminé d'arguments template, a l'heure actuel, tu n'as pas d'autre choix que d'écrire autant de version que de nombre d'argument géré. C'est très très lourd. Une autre solution plus simple est de passer une boost::tuple.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Août 2004
    Messages
    152
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2004
    Messages : 152
    Points : 70
    Points
    70
    Par défaut
    Excellent Nogane ! C'est tout à fait ça, Boost est vraiment très flexiable à ce que je vois. Tout a été prévu avec soin. Je suis très content, merci beaucoup à toi et à Davidbrcz.

    EDIT: J'ai des problèmes à la compilation, je vais voir si je m'en sors seul sinon je posterai si nécessaire.
    EDIT 2: Super, l'implémentation est parfaite, ça marche nickel. Le jeu a bien avancé grâce à cette technique, j'ai implementé la gestion des temps/intervalles des actions.

    Merci encore ! Résolu.

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

Discussions similaires

  1. Pointeur de fonction avec template
    Par ehmicky dans le forum Langage
    Réponses: 5
    Dernier message: 23/11/2010, 02h07
  2. Pointeur de fonction, Template, map et autres joyeusetés
    Par K2R Nolween dans le forum Langage
    Réponses: 6
    Dernier message: 20/05/2009, 04h14
  3. template et pointeur de fonction.
    Par ZaaN dans le forum Langage
    Réponses: 10
    Dernier message: 11/08/2007, 08h15
  4. Pointeur de fonction membre template
    Par bolhrak dans le forum Langage
    Réponses: 6
    Dernier message: 12/12/2006, 14h47
  5. Réponses: 13
    Dernier message: 03/10/2005, 18h06

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