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 :

pbm pointeurs sur fonction membre :)


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 10
    Points : 5
    Points
    5
    Par défaut pbm pointeurs sur fonction membre :)
    bonjour j'aimerais que kkun puisse me repondre...

    pour me familiariser avec le C++ je passe actuellement mon temps a faire un wrapper win32

    je voudrais avoir une classe MyApp qui contient un pointeur vers un MyWindow et que MyApp recoivent les evenements générés par MyWindow

    j'ai essayé avec sigc++ mais la librairie ne fonctionne pas en ce moment - probleme de compilation. j'aimerais pouvoir l'eviter, d'autant plus qu'elle fait bien dans les 2mb de taille.

    j'ai aussi trouvé sigslot qui tient dans seulement 4ko mais qui ne correspond apparament pas bien a mon besoin (assertion failed dans OnTerminate).....

    le besoin en question c'est d'avoir un evenement OnTerminate qui correspond au message WM_NCDESTROY

    une fois que MyApp recoit OnTerminate, il ne lui reste alors qu'a supprimer le pointeur vers MyWindow (delete + mise à NULL) comme ça le conteneur de l'objet est informé, la recupération (destruction des objets) de la memoire se fait de maniere efficace et claire.

    d'ailleurs je me permet de poser une question subsidiaire en passant... est ce que l'instruction "delete MyWindow" au sein de l'evenement Myapp->MyWindow_OnTerminate n'est pas une violation des principes ? En effet, à la sortie de OnTerminate on retourne dans un objet qui vient d'être détruit. de la même manière on pourrait peut être dire la même chose pour "delete this" qui va généralement produire un return depuis un objet qui vient aussi d'être détruit.

    j'en vient aux détails techniques et au problème proprement dit...

    La question est comment supprimer la référence à MyApp ci dessous dans la class Event. Je voudrais avoir une classe générique capable d'accepter un pointeur sur MyApp mais aussi sur n'importe quelle autre instance de classe. à chaque variation que je tente, le compilo me dit qu'il faut préciser une classe

    j'ai essayé différents style mais autant il semble simple de gérer le cas des pointeurs vers les fonctions globales, autant il semble complexe de faire de même avec les fonctions membres.

    j'espère avoir été clair Merci à ceux qui pourront répondre.

    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
     
    class Event
    {
        public:
            MyApp* m_PtrClassinstance; 
            void (MyApp::*m_PtrFunctionAddress)();
     
            //ce style n'est pas autorisé :(
            //void* m_PtrClassinstance; 
            //void (*m_PtrFunctionAddress)();
     
            void Operator()()
            {
                (m_PtrClassinstance->*m_PtrFunctionAddress)();
            }
    }
     
    class MyWindow
    {
         public:
            Event* OnClick;
     
            ...
            WndProc()
            {
               case WM_MOUSEUP:
                   OnClick(); // declenche l'evenement
            }
    }

  2. #2
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 4
    Points : 5
    Points
    5
    Par défaut
    J'ai pas tout compris mais je vais tenter de répondre.

    Pour ta première question, oui tu peut faire un delete this et revenir dans le l'objet détruit, cela ne viole aucun principe, c'est autorisé, à condition qu'après tu n'utilise pas this et donc aussi des objets membres car ils ont été aussi détruits, donc il faut bien faire attention à ce que tu fais:

    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
     
    class Appele
    {
       Appelant *a;
     
    public:
       void autre()
       {
       }
     
       a *supprime()
       {
          delete a;
     
          return a; // Bizarre mais ok
       }
    };
     
    class Appelant
    {
       Appele *a;
     
    public:
       void enleve()
       {
          Appelant *t= this;
          Appele *m= a;
     
          Appelant *r= a->supprime();
     
          if( this == r ) {...} // a eviter
          if( t == r ) {...} // ceci est mieux
          if( a == NULL ) {...} // ERREUR car a <=> this->a or ici l'objet pointé par this n'existe plus
          if( m == NULL ) {...} // ok, ceci est préférable à la ligne précédente
          a->autre(); // pareil: ERREUR car a <=> this->a
          m->autre(); // ok, ceci est ce qu'il faut faire
       }
    }
    Donc tu vois, il faut que l'appelant sauvegarde dans des variables gobales, ou ce qui est préférables, des variables locales, tout ce que tu as besoin d'utiliser apprès l'appel d'une fonction qui détruit l'appelant.


    Pour ta question principale, un membre qui est commun à toutes les instances d'une classe est un membre statique de cette meme classe. Et les pointeurs de méthodes sont spéciaux car les méthodes ont des paramètres cachés.

    En fait désolé de ne pas répondre entièrement à ta question car j'ai subitement quelque chose de préssé à faire, je terminerai si personne ne t'apporte pas une réponse qui te convienne.

  3. #3
    screetch
    Invité(e)
    Par défaut
    deux possibilités :

    - tout dans la classe de base (peu de chances que ca convienne)
    - event 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
    template< typename T >
    class Event
    {
        public:
            T* m_PtrClassinstance; 
            void (T::*m_PtrFunctionAddress)();
     
            void Operator()()
            {
                (m_PtrClassinstance->*m_PtrFunctionAddress)();
            }
    }
     
    class MyWindow
    {
         public:
            Event<MyWindow>* OnClick;
     
            ...
            WndProc()
            {
               case WM_MOUSEUP:
                   OnClick(); // declenche l'evenement
            }
    }

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    Corebreaker

    merci pour la reponse mais j'ai du mal m'expliquer....

    la question c'est comment un wrapper sur une fenêtre (class MyWindow) peut informer l'application (class MyApp) qu'il est necessaire de faire un delete de l'instance MyWindow - notament suite à la fermeture de la fenetre par l'utilisateur ?

    j'ai dabord essayé en faisant un template qui va servir à générer un evenement quelconque - OnTerminate() en l'occurence - et qui sera reçu par MyApp. lequel pourra faire un delete de l'instance MyWindow.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    template<typename T> class Event
    {
         public:
             T* m_PtrClassInstance;
             void (T::*m_PtrFunctionAddress)();
     
             void operator()()
             {
                 (m_PtrClassInstance->*m_PtrFunctionAddress)();
             }
    };
    la classe MyWindow.

    Je veux que MyWindow declenche un Event pour signaler à MyApp que la fenêtre à été fermée (par l'utilisateur) et qu'il faut donc que MyApp détruise l'instance de MyWindow.

    J'ai essayé differentes syntaxes pour la déclaration de OnTerminate.

    Et je reste bloqué sur <typename T> au niveau de la déclaration parce que MyWindow ne peut pas connaitre le type de l'appelant (MyApp) à l'avance. pourtant que le compilateur soit informé de ce type pour le template.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class MyWindow : public MyObject
    {
          //ici je reste bloqué... 
          Event<typename T> *OnTerminate;
     
          WndProc() 
         {
               switch(Msg)
                     case WM_NCDESTROY
                            OnTerminate();  //declenche l'event
         }
    }
    la classe MyApp

    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
     
    class MyApp
    {	
         MyWindow *Wnd;
     
         void Init()
         {
             Wnd = new MyWindow();
             Wnd->OnTerminate = new Event<cMyapp>;
             ... initialisation des membres de OnTerminate
         }
     
         void MyWindow_OnTerminate()
         {
            //reception du message OnTerminate
            delete Wnd;
            Wnd = NULL;
         }
     
    };

    comment faire ?

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par screetch Voir le message
    deux possibilités :

    - tout dans la classe de base (peu de chances que ca convienne)
    - event template
    oui j'y ai pensé avec un jeu d'interfaces et fonctions virtuelles pures mais ca oblige a implementer toute les OnMouseMove, OnMouseToto, OnKeyPress, etc... Alors qu'on en à pas vraiment besoin... Et je veux éviter l'utilisation des macros

    Un Event Template bien foutu oui mais pas comme sigslot, qui soit dit en passant est bien fait, mais qui toutefois ne correspond pas puisqu'il declenche une assertion failed sur le delete MyWindow (apparament un probleme de validité d'iterator dans un std::list utilisé par sigslot)

    voila... ca veut dire pour l'instant que ma classe n'est pas capable de generer un évenement à destination d'un autre classe..

    c'est terrible, ca fait 3 jours que je traine ça... je me suis dit qu'un appel au secours ici pourrait peut etre m'aider

  6. #6
    screetch
    Invité(e)
    Par défaut
    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
    class Event
    {
    public:
       virtual void void Operator()();
    };
     
    template< typename T >
    class TypedEvent
    {
        public:
            T* m_PtrClassinstance; 
            void (T::*m_PtrFunctionAddress)();
     
            void Operator()()
            {
                (m_PtrClassinstance->*m_PtrFunctionAddress)();
            }
    }
     
    class MyWindow
    {
         public:
            Event* OnClick;
     
            ...
            WndProc()
            {
               case WM_MOUSEUP:
                   (*OnClick)(); // declenche l'evenement
            }
    }
    mais la il faut passer par des pointeurs, ce qui va conduire a un probleme de proprietaire : qui possede l'event ?

  7. #7
    Membre confirmé

    Inscrit en
    Août 2007
    Messages
    300
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 300
    Points : 527
    Points
    527
    Par défaut
    Boost::Signals est prévu pour ça (cf. exemple proche).
    Si on veut tout refaire soi-même ("se familiariser avec C++"), il faut fournir à l'évènement appelant (équivalent des signaux boost) non seulement l'objet appelant (sauf si c'est une fonction statique), mais aussi la fonction à appeler elle-même (j'ai par ailleur paramétré l'application par le type de fenêtre).
    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
    struct Event_base { virtual void    operator () ( void ) { throw; } };
    template < class App >
    struct Event : public Event_base {
    typedef void (App::*callback_type) ( void );
    App *a_; callback_type c_;
    Event ( App *a, callback_type c ) : a_ ( a ), c_ ( c ) {}
    virtual void    operator () ( void ) { ((*a_).*c_)(); } };
     
    struct MyWindow
    {
          Event_base *OnTerminate;
          Event_base *OnClick;
     
         void WndProc() 
         {
               switch(Msg)
                     case WM_clicky
                          (*OnClick)();  //declenche l'event
                     case WM_NCDESTROY
                           *OnTerminate)();  //declenche l'event
         }
     
         ~MyWindow () { delete OnTerminate; delete OnClick; }
    };
     
     
    template < class window >
    struct  app {      window *Wnd;
     
    Event<app>* make_event ( void (app::*f) ( void ) ) {
        return ( new Event<app> ( this, f ) ); }
     
         void Init()
         {
             Wnd = new window();
             Wnd->OnTerminate   = make_event ( &app<window>::OnTerminate );
             Wnd->OnClick       = make_event ( &app<window>::OnClick );
         }
     
         void OnTerminate() { delete Wnd; Wnd = NULL; }
         void OnClick()     { std::cout << "app:click\n"; }
    };
     
    int main(int argc, char* argv[])
    {
    app<MyWindow>   a;
     
        a.Init();
    ...
    ... pourquoi ne pas réutiliser Boost.Signals, et tant qu'à faire Boost.Bind et Boost.Smart_ptr pour faire propre, validé, et surtout pérenne? (nombre des extensions C++0x viennent de Boost).
    "Maybe C++0x will inspire people to write tutorials emphasizing simple use, rather than just papers showing off cleverness." - Bjarne Stroustrup
    "Modern C++11 is not your daddy’s C++" - Herb Sutter

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    ac_wingless

    Merci pour ta réponse avec l'exemple, je vais l'étudier et répondre au plus vite.

    Cordialement

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Février 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    ac_wingless

    Bonjour !

    Desole de pas avoir pu repondre plus tot.

    Merci, ca marche bien. J'avais pas pensé en effet de zapper les déclarations dans MyWindow grace à la possibilité de mettre l'opérateur () en fonction virtuelle pure Bravo et encore merci de m'avoir aidé à ouvrir la voie :p

    Pour Boost, c'est bien mais j'ai une confiance relative dans ces classes d'objets tout comme dans la STL qui peut avoir des effets de bords (ce qui m'est arrivé avec sigslot et le OnTerminate)

    Est ce que ca veut dire que je peux faire mieux dans l'ensemble que ces librairies? probablement pas...

    mais je serais pas obligé de réviser toute ma stratégie de dev en cas de pbm.... Ca vaut ce que ca vaut comme vision... Je ferais un effort en ce qui concerne les hashtables et autres collections ultra complexes probablement, quoique ca peut tjrs etre interessant a etudier n'empeche.

    Etant quand même de la "vieille ecole" lol j'aime aussi avoir les programmes les plus petits possibles

    Encore 1000 merci pour ton aide.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 20/02/2008, 17h29
  2. [POO] Pointeur sur fonction membre et héritage
    Par MrDuChnok dans le forum C++
    Réponses: 9
    Dernier message: 20/07/2006, 18h19
  3. Pointeur sur fonction membre avec parametre
    Par Glosialabolas dans le forum C++
    Réponses: 7
    Dernier message: 06/02/2006, 03h32
  4. Réponses: 10
    Dernier message: 03/02/2005, 14h09
  5. Réponses: 5
    Dernier message: 12/01/2005, 21h58

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