Pointeur de fonction membre en C++ ??

Pointeur de fonction membre en C++ ?? - Programmation

Marsh Posté le 08-02-2002 à 12:32:23    

voila j'ai une grosse question en C++. En fait je pense que ce n'est pas possible ce que je veux faire, mais on ne sait jamais.
 
Es-ce qu'il est possible de faire des pointeurs de fonctions d'une classe en C++ comme on peut le faire en C ?
 
je m'explique. Je voudrais par exemple définir un type de pointeur de fonction (avec un paramètre int) d'une classe comme ceci :
// définition de ma classe
Class A
{
public :
    void fct1( int a );
    void fct2( int b );
}
 
// Définition du type pointeur sur une fonction membre de A.
typedef void (A::*pFonction)(int);
 
// Fonction qui reçoit une fonction membre de A et appele cette fonction
void CallFct( pFonction pFct, A* a, int i )
{
        // Appele à ma fonction membre
 a->pFct( i );
}
 
void main()
{
    A       a;
 
    CallFct( A::fct1, a, 0 );
    CallFct( A::fct2, a, 0 );
}
 
voila, c'est surement pas possible, mais on ne sait jamais. Si ça trouve c'est peut-être possible avec les fonctions virtuelles et les vfTable....
 
Bon sinon, si c'est pas possible je ferais des fonctions de classe statique qui prendront en premier paramètre un pointeur sur la classe. Mais si par hasard il y avait une autre solution.
 
François.

 

[jfdsdjhfuetppo]--Message édité par leander--[/jfdsdjhfuetppo]

Reply

Marsh Posté le 08-02-2002 à 12:32:23   

Reply

Marsh Posté le 08-02-2002 à 13:53:50    

Bien sûr c'est possible, mais, honnétement, c'est quoi l'intérêt? Pourquoi ne pas directement appeler la fonction membre concernée ou en créer une autre si ton CallFct fait plus de choses....(bien sûr il faut vraiment que ce soit TA classe :) ).
Surtout que dans ton CallFct tu passe aussi l'adresse de l'objet....(tu passe à la fois l'adresse de l'objet et l'adresse d'une de ses fonctions membres). Bref c'est monstrueux!
 
Tu écrit a->pFct( i ); alors que tu pourrais faire a->NomDeLaFonction( i );  
 
Toi aussi tu viens du C, c'est ca? :)
 
Pour la syntaxe:
typedef void (A::*pFonction)(int);  
a->*pFct( i );


---------------
Si t'es pas net, reste a la buvette
Reply

Marsh Posté le 08-02-2002 à 14:07:28    

Je ne peux pas appeller la fonction directement concerné parce que justement je ne le sais pas !!! Je ne suis pas bête non plus.
 
En fait je compte utiliser ce système dans un gestionnaire de message ou un classe s'abonnera à un evenement et enverra au gestionnaire, l'ID de l'evenement, le pointeur sur l'instance de la classe et le pointeur sur la fonction membre de la classe qui va traiter l'evenement.
 
Je pourrais faire ça, en utilisant une seule fonction virtuelle qui gère tous les evenements avec un switch mais je préfèrerais utliser des pointeurs sur des fonctions. C'est plus simple à utiliser.
 
Alors je ne vois pas du tout pourquoi tu me dis que je viens du C ... Je fais du C++ depuis 4/5 ans et j'aime pas trop le C ;)
 
Bon, voila pour l'explication. Sinon, j'ai essayé le bout de code que tu dis (en fait c'est ce que j'avais essayé mais je mettais trompé en le recopiant dans mon message).
Mais le compilateur me sors cette erreur :
"error C2628: 'A' followed by 'void' is illegal (did you forget a ';'?)"
Apparement le compilateur interprete A comme le nom du typedef...
Tu vois où peut-être le problème.
 
En tout cas, merci pour ta réponse.

Reply

Marsh Posté le 08-02-2002 à 14:14:33    

Pour une sombre raison on peut pas retirer de pointeurs sur une fonction membre sauf si elle est statique.
Je pense que cette sombre raison et que si on appelle une fonction par son adresse il va manquer le "this", et la fonction saura pas à quelle intance accéder.. D´où la restriction à static.. Si qqun peut confirmer.. ;)
 
Sinon je suis d´accord avec Willythekid ça sert à rien, autant utiliser des fcts virtuelles.. SAUF, qd on est obligé d´utiliser une pov vielle fct en C, genre pour le multithreading!! ;)
Dans ce cas comme le dit leander je passe le this à ma fct statique.. :)


---------------
Athlon64 s754 10*200MHz - R9800Pro - 512MB DDR200MHz - ZX6RR - Q2[SupOp] - Tutorial Video: multilangues, multisstitres
Reply

Marsh Posté le 08-02-2002 à 14:19:33    

en Pascal si on rajoute un "of object" à la fin de la déclaration ça marche. Y a pas un équivalent, un mot clé à rajouter ?
ex:

Code :
  1. type
  2.   TNotifyEvent = procedure (Sender: TObject) of object;


 
ça informe le compilo que c'est un pointeur vers une méthode et non une fonction classique

 

[jfdsdjhfuetppo]--Message édité par antp--[/jfdsdjhfuetppo]


---------------
mes programmes ·· les voitures dans les films ·· apprenez à écrire
Reply

Marsh Posté le 08-02-2002 à 14:38:45    

C'est aussi ce que je pensais à propos des fonctions membres. On est obligé d'avoir le 'this' pour pouvoir les appeler. Mais je me disais qu'il y avait peut-être un moyen de contourner d'une façon ou une autre. Et qu'a la manière des fonctions virtuelles, on pourrai imagine que le pointeur d'une fonction membre soit juste un décalage et que le pointeur 'this' permet de récupérer à partir du décalage, la vrai fonction membre.
C'est pour cela, quand paramètre j'ai mis le pointeur de fonction et son objet puisqu'en C++ ils sont bien sur indissociable.
ça peut sembler tourdu, mais ça me parait logique. Maintenant faut voir comme les compilos gèrent les adresses des fonctions membres.
 
Et donc comme je disais précédemment, les fonctions virtuelles ne jouent pas le role souhaiter. Je vais remettre un exemple plus clair de ce que je souhaiterais.
 
Class A
{
public:
     void fct1();
     void fct2();
     void fct3();
}
 
// déclaration des evenements
{
    RegisterEvt( ID_SOUND, A::fct1, A );
    RegisterEvt( ID_WALK, A::fct2, A );
    RegisterEvt( ID_BIDON, A::fct3, A );
}
 
// Gestion des evenements
{
    for(i=0; i<NbEvementRecord; i++)
    {
        if( EvtRecord[i].id == evtCurrent)
        {
             // Et ici on appelle la methode de la bonne classe
             // associé à l'evement courant.
             EvtRecord[i].Class->EvtRecord[i].Fct();
        }
     }
}
 
Es-ce que c'est plus clair ? et surtout es-ce que c'est possible ? Faut peut-être bidouiller avec les fct viruelles, non ?

Reply

Marsh Posté le 08-02-2002 à 14:47:36    

leander a écrit a écrit :

 
...
 
Es-ce que c'est plus clair ? et surtout es-ce que c'est possible ? Faut peut-être bidouiller avec les fct viruelles, non ?  




 
Il FAUT absolument que tu utilises le mécanisme des fonctions virtuelles, c'est exactement le cas typique en C++, tu devrais le voir instantanément. Ce que tu es en train de coder est bidouillatoire (très fortement inspiré des callback du C) et sans doute non portable, en tout cas c'est vilain.
 
C'est le pattern classique des ecouteurs et des abonnés (je me rappelle plus le nom).


---------------
"Dieu a exploité tous nos complexes d'infériorité, en commençant par notre incapacité de croire à notre propre divinité." - Emil Michel Cioran
Reply

Marsh Posté le 08-02-2002 à 14:52:56    

je sais bien que c'est un système de callback. Mais je ne vois pas comment le coder avec les fonctions virtuelles.
Tu pourras pas me montrer en 2s ??
 
Sinon, pour le pattern ecouteurs ou abonnés, il ne me semble pas qu'il y soit dans le bouquin 'design pattern' que j'ai ici.

Reply

Marsh Posté le 08-02-2002 à 15:00:06    

Oui on peut faire ce que tu veux, et c'est portable (enfin c'est dans la norme).
Seulement un heritage est plus elegant, et si ton objet doit repondre a plusieurs evenements c'est sans doute qu'il est trop gros, ce que je te conseille c'est des inner classes, je sais ca fait tres Java, mais bon
 
normalement les inners class ont acces a tous les elements de la classe encapsulante... (encore une fois c'est la norme)

Reply

Marsh Posté le 08-02-2002 à 15:01:42    

leander a écrit a écrit :

je sais bien que c'est un système de callback. Mais je ne vois pas comment le coder avec les fonctions virtuelles.
Tu pourras pas me montrer en 2s ??
 
Sinon, pour le pattern ecouteurs ou abonnés, il ne me semble pas qu'il y soit dans le bouquin 'design pattern' que j'ai ici.  




Le nom francais c'est l'Observateur...

Reply

Marsh Posté le 08-02-2002 à 15:01:42   

Reply

Marsh Posté le 08-02-2002 à 15:02:13    

C moi qui merde sur la syntaxe :)
Désolé:
 
(a->*pFct)(i);


---------------
Si t'es pas net, reste a la buvette
Reply

Marsh Posté le 08-02-2002 à 15:04:27    

J'essaie de compiler ca et je te dis
 
// définition de ma classe
Class A
{
public :
   void fct1( int a );
   void fct2( int b );
}
 
// Définition du type pointeur sur une fonction membre de A.
typedef void (A::*pFonction)(int);
 
// Fonction qui reçoit une fonction membre de A et appele cette fonction
void CallFct( pFonction pFct, A* a, int i )
{
       // Appele à ma fonction membre
       (a->*pFct)(i);
}
 
void main()
{
   A       a;
 
   CallFct( A::fct1, &a, 0 );
   CallFct( A::fct2, &a, 0 );
}


---------------
Si t'es pas net, reste a la buvette
Reply

Marsh Posté le 08-02-2002 à 15:07:39    

merci Benb, je vais regarder. Mais il me semblait que l'observateur était plutot utiliser dans le cas d'une gestion vue document ou il n'y avait qu'un seul type d'evenement qui était envoyé à l'objet.  
 
Sinon, pour l'héritage, je ne vois pas comment faire, puisque mon gestionnaire d'évènement ne connait pas le type des evenements (et surtout parce que c'est des ID).
Alors peut-être qu'il faudrait que je revois la façon dont son envoyer les evenements...
 
 
Sinon, Willythekid, lorsque je parlais d'erreur de compilation, ceci concernait le typedef, pas l'appel. Tu n'as pas d'erreur toi ??

Reply

Marsh Posté le 08-02-2002 à 15:15:10    

Ca passe chez moi sur Visual6. Au passage, le problème du "this" se pose aussi puisque fctx, fonction membre non static, doit forcement recevoir un "this". Il lui est passé en définissant a quelle classe on se réfère. D'où le "a->*pFct".
 
Pour le reste, si c'est ca que tu veux faire, cette bidouille t'es absolument inutile. En java, les événements sont gérés avec un zest de classe, d'héritage et de fonctions virutelles (pure parfois). Observer, Event Handler, Event Notifier, etc...


---------------
Si t'es pas net, reste a la buvette
Reply

Marsh Posté le 08-02-2002 à 15:16:21    

leander a écrit a écrit :

merci Benb, je vais regarder. Mais il me semblait que l'observateur était plutot utiliser dans le cas d'une gestion vue document ou il n'y avait qu'un seul type d'evenement qui était envoyé à l'objet.  
 
Sinon, pour l'héritage, je ne vois pas comment faire, puisque mon gestionnaire d'évènement ne connait pas le type des evenements (et surtout parce que c'est des ID).
Alors peut-être qu'il faudrait que je revois la façon dont son envoyer les evenements...
 
 
Sinon, Willythekid, lorsque je parlais d'erreur de compilation, ceci concernait le typedef, pas l'appel. Tu n'as pas d'erreur toi ??  




Le design pattern est une vue de base, a toi de l'adapter a tes besoins...
ID des evenements au moment ou tu enregistre l'observateur
ID des evenement au moment ou te le notifie
Attribut de l'observe que l'observateur lis une fois notifie (c'est ce tend a proposer le design pattern)
ou encore differents observateurs en fct du type de l'evenement : la methode d'enregistrement est surchargee pour chaque type d'observateur... (ce serait me preference...)

Reply

Marsh Posté le 08-02-2002 à 15:18:58    

Oups désolé, j'ai répété ce que tout le monde a déjà dit :D


---------------
Si t'es pas net, reste a la buvette
Reply

Marsh Posté le 08-02-2002 à 15:23:55    

leander a écrit a écrit :

 
Sinon, Willythekid, lorsque je parlais d'erreur de compilation, ceci concernait le typedef, pas l'appel. Tu n'as pas d'erreur toi ??  




 
T'as pas oublié le ";" après la déf de la classe?? :D On sait jamais :D
 
Class A  
{  
public :  
   void fct1( int a );  
   void fct2( int b );  
};


---------------
Si t'es pas net, reste a la buvette
Reply

Marsh Posté le 08-02-2002 à 15:24:01    

Willythekid a écrit a écrit :

Oups désolé, j'ai répété ce que tout le monde a déjà dit :D  




bis repetitas placent

Reply

Marsh Posté le 08-02-2002 à 15:24:54    

ok merci bcp 'Willythekid'.
En fait dans le code que tu m'as mis, c'était le même que chez moi, avec le même bug ;)
Il n'y avait pas de ';' après la fin de la déclaration de la classe.
C'est pour cela qu'il me sortait une erreur à la con.
Enfin, maintenant ça marche, c'est ce que je voulais.
 
Sinon, benb merci pour tes conseils. Je vais relire attentivement l'observateur et voir si ce n'est pas une meilleure solution.
Mais en fait, j'ai des contraintes de place mémoire (très très peu de mémoire) et de temps d'éxecution pour mon problème. Donc ce n'est pas sur que l'observeur soit satisfaisant. Mais qui sait ;)
 
encore merci

Reply

Marsh Posté le 08-02-2002 à 15:39:34    

leander a écrit a écrit :

ok merci bcp 'Willythekid'.
En fait dans le code que tu m'as mis, c'était le même que chez moi, avec le même bug ;)
Il n'y avait pas de ';' après la fin de la déclaration de la classe.
C'est pour cela qu'il me sortait une erreur à la con.
Enfin, maintenant ça marche, c'est ce que je voulais.
 
Sinon, benb merci pour tes conseils. Je vais relire attentivement l'observateur et voir si ce n'est pas une meilleure solution.
Mais en fait, j'ai des contraintes de place mémoire (très très peu de mémoire) et de temps d'éxecution pour mon problème. Donc ce n'est pas sur que l'observeur soit satisfaisant. Mais qui sait ;)
 
encore merci  




mefie toi des aprioris...
une liste de pointeurs sur des classe prends moins de place qu'une liste de couples poiteurs sur classe + pointeur sur membre et en vitesse d'execution c'est identique a mon avis...

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed