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 :

Héritage et pointeurs de méthode


Sujet :

Langage C++

  1. #1
    Membre expérimenté
    Profil pro
    Étudiant
    Inscrit en
    Avril 2007
    Messages
    181
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2007
    Messages : 181
    Par défaut Héritage et pointeurs de méthode
    Bonjour, j'ai une question sur les bonnes pratiques du C++ !

    Soit la classe "Parent", dont hérite la classe "Enfant".

    J'ai besoin de passer un pointeur de méthode de la classe Enfant en paramètre, là ou un pointeur de méthode de la classe Parent est attendu, ce qui ne compile pas car les deux types sont différents.
    (Le principe de substitution ne s'applique pas sur les pointeurs de méthodes).

    Il n'est donc pas possible de faire :

    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 Parent
    {
    };
     
    class Enfant: public Parent
    {
    public:
    	void methode(int)
    	{
    	}
    };
     
    void f(void (Parent::*callback)(int))
    {
    }
     
    int main()
    {
    	f(&Enfant::methode);
    }
    L'appel à la fonction f provoque l'erreur de compilation, le type de la méthode n'est pas bon.
    Pour contourner le problème, je caste :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main()
    {
    	typedef void (Parent::*HACK)(int);
    	f((HACK) &Enfant::methode);
    }
    Est-il correct de caster, il n'y a pas de risque à l'exécution ?
    Existe-t-il une solution plus élégante ?

    Merci.

  2. #2
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    La question à se poser est plutôt : pourquoi as-tu besoin de faire ça ?
    Normalement, t'aurais plutôt une fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void callback(Parent& /* ou un pointeur */ p)
    {
      p.callback(); // ou p->callback() si pointeur
    }
    Et ensuite tu envoies cette fonction callback et l'instance sur laquelle tu veux l'appeler à une autre fonction
    Enfin, il faut que tu expliques ta situation concrète pour t'orienter vers quelque chose de plus correct, car ce que tu fais ci-dessus n'est clairement pas idéal

  3. #3
    Membre expérimenté
    Profil pro
    Étudiant
    Inscrit en
    Avril 2007
    Messages
    181
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2007
    Messages : 181
    Par défaut
    Salut,

    J'avoue que je m'y attendais un peu au "pourquoi"
    J'ai réduit le plus possible le code pour simplifier la compréhension du problème.

    Alors le contexte : je programme un petit système d'interface graphique.

    Parent est la classe abstraite Window.
    Enfant est la classe MyWin (qui implémente les éléments de la fenêtre et hérite donc de Window).

    On peut mettre des boutons dans la fenêtre (classe Button), Window contient une liste de Button* (non représenté).

    Le problème est de définir un système de callback, celle-ci devant être déclenchée par le bouton, mais implémentée par MyWin.
    Désolé pour la longueur du code, mais au moins l'exemple compile et ce que je cherche à faire doit apparaître plus clairement :


    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
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <cstdlib>
     
    class Button;
     
    class Window
    {
    public:
    	void AddButton(Button* b)
    	{
    		// ajout du bouton dans la fenêtre, qui est son gestionnaire
    		// (affichage, gestion events, desallocation, etc)
    	}
    };
     
     
    class Button
    {
    public:
    	Button(Window* owner, int x, int y)
    	{
    		owner->AddButton(this);
    		owner_ = owner;
    		callback_ = NULL;
    	}
     
    	void SetCallback(void (Window::*callback)(Button*))
    	{
    		callback_ = callback;
    	}
     
    	void OnClick()
    	{
    		if (callback_ != NULL)
    		{
    			(owner_->*callback_)(this);
    		}
    	}
     
    private:
    	void (Window::*callback_)(Button*);
    	Window* owner_;
    };
     
     
    class MyWin: public Window
    {
    public:
    	MyWin()
    	{
    		typedef void (Window::*HACK)(Button*);
     
    		button_ = new Button(this, 42, 42);
    		button_->SetCallback((HACK) &MyWin::Hey); // ne compile pas, sauf si cast !
    	}
     
    	void Hey(Button* emitter)
    	{
    		// le code de la callback
    	}
    private:
    	Button* button_;
    };
     
    int main()
    {
    	MyWin pouet;
    }
    Bon, j'aime bien ce système (peut être as-tu remarqué l'influence de Qt ) .
    Il permet d'associer plusieurs fois la même callback à différents widgets (ici des boutons), et de découper en méthodes chaque callback.
    De plus on a pas à se trimballer des ID (comme c'est souvent le cas dans les modules de GUI "fait maison").

  4. #4
    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 : 33
    Localisation : Suisse

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

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Au lieu d'utiliser des CallBack C tout moche, quid de boost::function et de boost::bind ?

    Pus propre, plus efficace, plus sûr
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  5. #5
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Au lieu d'utiliser un callback C, pourquoi ne pas utiliser une interface et un objet de hook ?

  6. #6
    Membre expérimenté
    Profil pro
    Étudiant
    Inscrit en
    Avril 2007
    Messages
    181
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2007
    Messages : 181
    Par défaut
    boost est une bibliothèque géniale, mais je n'ai pas très envie d'ajouter une dépendance supplémentaire à mon projet juste pour gérer les callbacks...

    J'ai essayé de bricoler avec std::mem_fun de STL <functional> mais le problème est toujours le même car le type de la classe diffère.

    Je cherche une solution simple à mettre en place avant tout...

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 17
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 57
    Par défaut
    Comme ça?

    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
    class Parent
    {
    };
     
    class Enfant: public Parent
    {
    public:
    	void methode(int)
    	{
    	}
    };
     
    template <class DeriveParent>
    void f(void (DeriveParent::*callback)(int))
    {
    }
     
    int main()
    {
    	f(&Enfant::methode);
    }
    ?

Discussions similaires

  1. Pointeur sur méthode + héritage
    Par Bleastou dans le forum C++
    Réponses: 20
    Dernier message: 22/09/2008, 14h54
  2. TIdFTP, pointeur de méthode et procédure normale
    Par marcpleysier dans le forum Delphi
    Réponses: 4
    Dernier message: 05/01/2007, 10h30
  3. Réponses: 4
    Dernier message: 03/07/2006, 22h52
  4. [C++] Tableau de pointeurs de méthode ?
    Par Castagnems dans le forum C++
    Réponses: 13
    Dernier message: 15/05/2006, 16h45
  5. Pointeur de méthode
    Par John Fullspeed dans le forum Langage
    Réponses: 3
    Dernier message: 24/09/2004, 16h04

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