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 :

Adresse d'une méthode de classe


Sujet :

Langage C++

  1. #1
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut Adresse d'une méthode de classe
    Bonjour,
    Je suis en train de faire un petit projet avec la librairie Wii Yourself qui permet de connecter une Wiimote à son programme.

    Dans le fichier Demo.cpp, il y a trois fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void on_state_change (wiimote &remote, state_change_flags  changed, const wiimote_state &new_state){//code.....}
     
     
    void PrintTitle (HANDLE console){//code.....}
     
    int _tmain (){//code.....}
    Bref, heureusement ça marche parfaitement.

    Comme j'ai voulu l'intégrer dans autre projet, j'ai voulu regrouper les éléments de Demo.cpp dans une classe.
    Ainsi, voilà ce que j'ai rajouté dans Demo.h :
    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
    #include "libs\wiimote.h"
    class WiimoteHandler {
    private:
    	HANDLE console;
    	wiimote_sample sine_sample, daisy_sample;
    	wiimote remote;
     
    	void printTitle(HANDLE console);
     
    	void on_state_change(wiimote			  &remote,
    		state_change_flags  changed,
    		const wiimote_state &new_state);
     
    public:
     
    	int demo_wiimote();
     
    };
    Remarquez la fonction _intmain() qui est devenu demo_wiimote().

    Maintenant, les trois fonctions citées précédemment, sont désormais membre de la classe WiimoteHandler.

    J'ai étais donc contraint de changer cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    remote.ChangedCallback		= on_state_change;
    en quelque chose qui ressembla à ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    remote.ChangedCallback =  WiimoteHandler::on_state_change;
    ou ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    remote.ChangedCallback =  this->on_state_change;
    Malheureusement, ça ne marche pas alors que ça devrait le faire...

    Voilà l'erreur que j'ai :
    Erreur C3867 'WiimoteHandler::on_state_change'*: syntaxe non-standard*; utilisez '&' pour créer un pointeur vers un membre myproj e:\3d lab\opengl-bullet\myproj\demo.cpp 152

    Erreur C2440 '='*: impossible de convertir de 'void (__cdecl WiimoteHandler::* )(wiimote &,state_change_flags,const wiimote_state &)' en 'state_changed_callback' myproj e:\3d lab\opengl-bullet\myproj\demo.cpp 152
    Sauf qu'avec la première manière de faire, Visual me met du rouge sur le signe égal...


    Je suis perdu...

    Petits indices, qui pourront vous aider à m'aider () :
    -la variable remote est de type wiimote qui est une classe définie dans wiimote.h,
    -ChangedCallback est un champ de la classe wiimote de type state_changed_callback,
    -state_changed_callback est définie comme cela au début du fichier wiimote.h : typedef void (*state_changed_callback) (class wiimote &owner, state_change_flags changed, const wiimote_state &new_state); soit un pointeur de fonction renvoyant void qui a les mêmes paramètres que WiimoteHandler::on_state_change.

    Remarque, lorsque la fonction on_state_change ne fait pas parti de WiimoteHandler, ça marche. Mais je veux qu'elle fasse parti de la classe justement...
    J'aimerais tellement comprendre la source de mon problème....
    Merci pour votre aide.

  2. #2
    Expert éminent
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    juillet 2013
    Messages
    3 168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : juillet 2013
    Messages : 3 168
    Points : 7 071
    Points
    7 071
    Par défaut
    En cherchant sur les Internets, tu vas trouver le problème et approfondir le sujet

    Mais en gros en C++, une méthode est une fonction qui est liée à une classe. Et donc ton pointeur de fonction ne fonctionne pas, parce qu'elle est libre.

    void (*state_changed_callback) (XXX) est différent de void (WiimoteHandler::*state_changed_callback) (XXX) qui est différent de void (Dummy::*state_changed_callback) (XXX) (XXX étant la même signature).
    Ton compilateur te le dit clairement

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    1 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 1 055
    Points : 5 373
    Points
    5 373
    Par défaut
    Bonjour,

    Ta première ligne récupère bien l'adresse de la fonction (mais c'est une fonction membre donc inutilisable sans avoir l'objet.)
    Ta seconde ligne cherche à ajouter l'objet associé mais aucune syntaxe simple ne permet cela.
    Depuis le C++11, une fonction lambda a la particularité d'être convertible en pointeur de fonction qui sert de relai. Ça donnerait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    remote.ChangedCallback = [=](wiimote &remote, state_change_flags changed,const wiimote_state &new_state){ return this->on_state_change(remote,changed,new_state); };

  4. #4
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut
    Citation Envoyé par dalfab Voir le message
    Depuis le C++11, une fonction lambda a la particularité d'être convertible en pointeur de fonction qui sert de relai. Ça donnerait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    remote.ChangedCallback = [=](wiimote &remote, state_change_flags changed,const wiimote_state &new_state){ return this->on_state_change(remote,changed,new_state); };
    Je viens d'essayer cette technique de lambda, mais d'emblée Visual me met du rouge sur le crochet contenant le signe égal...
    En compilant j'ai ça comme erreur :
    Erreur C2440 '='*: impossible de convertir de 'WiimoteHandler::demo_wiimote::<lambda_d41c6fbb798b88d76128e179c8d6ad81>' en 'state_changed_callback' myproj e:\3d lab\opengl-bullet\myproj\demo.cpp 153

  5. #5
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut
    Citation Envoyé par foetus Voir le message
    En cherchant sur les Internets, tu vas trouver le problème et approfondir le sujet

    Mais en gros en C++, une méthode est une fonction qui est liée à une classe. Et donc ton pointeur de fonction ne fonctionne pas, parce qu'elle est libre.

    void (*state_changed_callback) (XXX) est différent de void (WiimoteHandler::*state_changed_callback) (XXX) qui est différent de void (Dummy::*state_changed_callback) (XXX) (XXX étant la même signature).
    Ton compilateur te le dit clairement
    Du coup, si typedef void (*state_changed_callback) (class wiimote &owner, state_change_flags changed, const wiimote_state &new_state); défini dans le fichier wiimote.h est différent de void (WiimoteHandler::*state_changed_callback) (class wiimote &owner, state_change_flags changed, const wiimote_state &new_state); ... Il faudrait faire quoi du coup? Il faut que je définisse le type void (*state_changed_callback) dans la classe WiimoteHandleret ça résoudrait les problèmes?

  6. #6
    Expert éminent
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    juillet 2013
    Messages
    3 168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : juillet 2013
    Messages : 3 168
    Points : 7 071
    Points
    7 071
    Par défaut
    Citation Envoyé par ABD-Z Voir le message
    Il faudrait faire quoi du coup?
    Cela va dépendre de ton code et à toi de voir Mais je dirais

    1) Soit tu fais ta callback avec un pointeur de méthode. Mais c'est une contrainte très forte, parce que tu vas avoir toutes tes callback dans une même classe

    2) Soit tu fais comme l'a proposé @dalfab
    Une fonction qui va appeler ta méthode. Tu as 2 façons de faire : soit une fonction libre soit une lambda (exemple de @dalfab)

    Mais avec une lambda il faut compiler avec la norme C++11 ou plus récente (C++14, C++17, ...) : il faut aller dans les options ... et si tu ne peux pas compiler c'est que ton Visual n'est pas à jour parce que le C++11 est par défaut depuis 2017

    Le problème de cette solution c'est que tu vas devoir avoir ton objet en variable globale ... ou réussir à le passer en paramètre (soit avec un cast (C) soit avec le polymorphisme (C++))

    Édit : @dalfab dans son message ci-dessous utilise un pointeur statique pour éviter la variable globale. Donc lorsque je dis "variable globale", c'est façon de parler et tu peux trouver d'autres façons plus appropriée/ maintenable/ ...

    3) Tu refais tout et tu codes un système de messages asynchrones. Une fois que ta tâche a fini, elle envoie un message "j'ai fini" qui sera intercepté par un observateur, qui ensuite, va prévenir les objets en attente.

  7. #7
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    1 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 1 055
    Points : 5 373
    Points
    5 373
    Par défaut
    Citation Envoyé par ABD-Z Voir le message
    Il faudrait faire quoi du coup? Il faut que je définisse le type void (*state_changed_callback) dans la classe WiimoteHandleret ça résoudrait les problèmes?
    Non, if faut fournir le type qui est attendu donc il faut lui donner un void (*state_changed_callback) (class wiimote &owner, state_change_flags changed, const wiimote_state &new_state).
    pour le lambda, il faut peut être une conversion explicite pour que ça soit accepté.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    remote.ChangedCallback = static_cast<state_changed_callback>([=](wiimote &own, state_change_flags chgst,const wiimote_state &nwst){ this->on_state_change(own,chgst,nwst); });
    Sinon on doit passer par une fonction relais.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    static WiimoteHandler *ObjetDestinataire;
    static void callback_relais(wiimote &owner, state_change_flags changed, const wiimote_state &new_state) {
        ObjetDestinataire->on_state_change( owner, changed, new_state );
    }
    ... ... ... ... ... ...
            ObjetDestinataire = this;
            remote.ChangedCallback = &callback_relais;

  8. #8
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut
    Du coup,
    Demo.h :
    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
    #include "libs\wiimote.h"
    class WiimoteHandler {
    private:
    	HANDLE console;
    	wiimote_sample sine_sample, daisy_sample;
    	wiimote remote;
     
    	void printTitle(HANDLE console);
     
    	void on_state_change(wiimote			  &remote,
    		state_change_flags  changed,
    		const wiimote_state &new_state);
     
    public:
     
    	int demo_wiimote();
    	static WiimoteHandler *ObjetDestinataire;
    	static void callback_relais(wiimote &owner, state_change_flags changed, const wiimote_state &new_state) {
    		ObjetDestinataire->on_state_change(owner, changed, new_state);
    	}
     
    };
    et ensuite dans Demo.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ObjetDestinataire = this;
    	remote.ChangedCallback = &callback_relais;
    Mais ça marche toujours pas...


    Erreur LNK2001 symbole externe non résolu "public: static class WiimoteHandler * WiimoteHandler::ObjetDestinataire" (?ObjetDestinataire@WiimoteHandler@@2PEAV1@EA) myproj E:\3d lab\opengl-bullet\myproj\Demo.obj 1

    Erreur LNK1120 1 externes non résolus myproj E:\3d lab\opengl-bullet\x64\Release\myproj.exe 1

  9. #9
    Expert éminent
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    juillet 2013
    Messages
    3 168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : juillet 2013
    Messages : 3 168
    Points : 7 071
    Points
    7 071
    Par défaut
    Citation Envoyé par ABD-Z Voir le message
    Mais ça marche toujours pas...
    C'est normal et ton problème est trivial

    Réfléchi un peu , on parle de fonction externe/ variable globale.

    Et pour ton problème, va voir les cours sur les membres et fonctions statiques dans une classe

  10. #10
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut
    Citation Envoyé par foetus Voir le message
    C'est normal et ton problème est trivial

    Réfléchi un peu , on parle de fonction externe/ variable globale.

    Et pour ton problème, va voir les cours sur les membres et fonctions statiques dans une classe

    Tu peux m'aider du coup, stp...
    Faut faire comment???
    Je suis complètement perdu

  11. #11
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    1 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 1 055
    Points : 5 373
    Points
    5 373
    Par défaut
    Pour te débloquer,
    La déclaration de la variable de classe static WiimoteHandler *ObjetDestinataire; doit être suivie d'une définition de cette variable à mettre dans le .cpp WiimoteHandler *WiimoteHandler::ObjetDestinataire;. Il existe d'autres solutions depuis le C++17. Mais pense à lire les tutoriels du site, ils sont pleins d'informations intéressantes et qui répondent à tes problèmes

  12. #12
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut
    Effectivement, j'allais le dire, mais mon ordi a crache et je suis allé dormir...
    J'ai donc mis la variable static et la fonction static dans le fichier Demo.cpp (et non pas dans la classe, dans Demo.h, WiimoteHandler en public) et là ça marche...
    Et ah oui, j'ai changé la visibilité de on_stage_change en public, elle était en privé... ce qui n'aidait pas trop
    Mais ce que j'aimerais bien comprendre, c'est pourquoi il faut passer par tout ça avec une fonction d'une classe?

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    septembre 2005
    Messages
    27 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : septembre 2005
    Messages : 27 086
    Points : 40 417
    Points
    40 417
    Par défaut
    Ton problème, c'est qu'apparemment l'auteur de la bibliothèque Wii Yourself a oublié qu'une bonne fonction "callback" accepte en plus du reste un paramètre de contexte: Un paramètre qui permet d'associer la fonction à une donnée... comme par exemple un pointeur d'objet C++.

    Résultat, ton callback (qui vu que tu n'es pas en C++11, ne peut être qu'un pointeur de fonction libre/statique) ne peut même pas recevoir en paramètre un objet auquel transmettre l'appel!

    Mais ce que j'aimerais bien comprendre, c'est pourquoi il faut passer par tout ça avec une fonction d'une classe?
    C'est parce qu'une fonction de classe cache un paramètre dans son prototype. Si tu écris:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class MaClasse
    {
    public:
    	void MaMéthode(int a);
    };
    Tu obtiens en fait une fonction dont le vrai prototype est void fonction(MaClasse* this, int a). Et donc, tu ne peux pas la passer en callback quand le prototype attendu est void fonction(int).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre actif
    Avatar de ABD-Z
    Homme Profil pro
    Étudiant
    Inscrit en
    septembre 2016
    Messages
    89
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : septembre 2016
    Messages : 89
    Points : 232
    Points
    232
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Ton problème, c'est qu'apparemment l'auteur de la bibliothèque Wii Yourself a oublié qu'une bonne fonction "callback" accepte en plus du reste un paramètre de contexte: Un paramètre qui permet d'associer la fonction à une donnée... comme par exemple un pointeur d'objet C++.

    .
    .
    .
    Merci! C'est plus clair maintenant!

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

Discussions similaires

  1. Récupérer l'adresse d'une méthode de classe
    Par kisaya dans le forum WinDev
    Réponses: 5
    Dernier message: 08/10/2008, 09h45
  2. Réponses: 3
    Dernier message: 02/01/2007, 14h53
  3. Réponses: 4
    Dernier message: 29/01/2006, 18h54
  4. [C#] Ajout d'une méthode à la classe DropDownList
    Par Scorff dans le forum ASP.NET
    Réponses: 2
    Dernier message: 30/08/2005, 15h23
  5. Réponses: 4
    Dernier message: 27/06/2005, 20h26

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