Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

pointeur sur une fonction membre d'une classe heritée

2 réponses
Avatar
Alex BLAIS
Bonjour,

je ne parviens pas à trouver la declaration édequate pour une pointeur
sur une fonction membre d'une classe héritée (si j'ai bien compris, en
effet la classe 'autre' est bien une classe héritée de 'base' ??) :

-je n'arrive pas à touver la déclaration de la variable onclick,
et de fait, la déclaration de la fonction set_onclick n'est pas bonne
non plus.


si je suis assez clair, qqun peut il m'aider ?


class base
{
public:
void (*onclick)(void); //n'est pas correcte

//
//permet de definir le pointeur onclick qui sera appelé
//avec mouse_click(a,b)
//

void set_onclick(void (*ptr)(void)) //n'est pas correct
{
onclick=ptr;
};

//
// sur mouse_click on appelle la fonction pointée par onclick
//

void mouse_click(int a,int b)
{
if (onclick!=NULL) onclick();
};
};


class autre : public base
{
public:


autre::autre (void)
{
set_onclick(&autre::toto);
};

//
// une fct toto qui fait beep
//

void toto(void)
{
sound(200);
delay(100);
nosound();
};
};

2 réponses

Avatar
Cyrille
Bonjour,

je ne parviens pas à trouver la declaration édequate pour une pointeur
sur une fonction membre d'une classe héritée (si j'ai bien compris, en
effet la classe 'autre' est bien une classe héritée de 'base' ??) :

-je n'arrive pas à touver la déclaration de la variable onclick,
et de fait, la déclaration de la fonction set_onclick n'est pas bonne
non plus.


si je suis assez clair, qqun peut il m'aider ?


Le type de toto est void (autre::*)(void), c'est-à-dire que c'est une
fonction membre de "autre", alors que void (*)(void) désigne une
fonction libre. On ne peut convertir l'un à l'autre. On ne peut non plus
convertir un void (autre::*)(void) en un void (base::*)(void), si je ne
m'abuse, sauf reinterpret_cast de sauvage, bien sûr, dont j'ignore ce
que ça peut donner.
Vous devez donc utiliser void (autre::*)(void).

Cependant le C++ permet des choses bien plus souples pour ce genre de
choses. Regardez les bibliothèques libsigc++ et Boost.Signals. Avec
cette dernière vous pourriez écrire ainsi ce que vous voulez faire:

#include <boost/signal.hpp>
#include <boost/bind.hpp>


class base
{
public:
boost::signal<void ()> onclick;

void mouse_click(int a,int b)
{
onclick();
};
};


class autre : public base
{
public:
autre::autre (void)
{
onclick.connect(boost::bind(&autre::toto, this));
};

//
// une fct toto qui fait beep
//

void toto()
{
sound(200);
delay(100);
nosound();
};
};

--
C'est ma signature qu'elle est la mieux. Pas la vôtre.

Avatar
kanze
Cyrille wrote:

je ne parviens pas à trouver la declaration édequate pour
une pointeur sur une fonction membre d'une classe héritée
(si j'ai bien compris, en effet la classe 'autre' est bien
une classe héritée de 'base' ??) :

-je n'arrive pas à touver la déclaration de la variable
onclick, et de fait, la déclaration de la fonction
set_onclick n'est pas bonne non plus.

si je suis assez clair, qqun peut il m'aider ?


Le type de toto est void (autre::*)(void), c'est-à-dire que
c'est une fonction membre de "autre", alors que void (*)(void)
désigne une fonction libre. On ne peut convertir l'un à
l'autre. On ne peut non plus convertir un void
(autre::*)(void) en un void (base::*)(void), si je ne m'abuse,
sauf reinterpret_cast de sauvage, bien sûr, dont j'ignore ce
que ça peut donner.


Ça marche aussi avec static_cast. Le résultat est garanti de
marcher si lors de l'appel, le type dynamique de l'objet
contient la fonction en question, c-à-d ici qu'il est autre, ou
une classe qui dérive d'autre.

Vous devez donc utiliser void (autre::*)(void).


Dans la classe de base, c'est un peu problèmatique, non ? Si
base a une fonction :
set_onclick( void (base::*ptr)() ) ;
autre peut bien l'appeler avec :
set_onclick( static_cast< void (base::*ptr)() >( &autre::toto ) ) ;

Ceci dit, je ne suis pas vraiment convaincu que c'est la bonne
solution. À mon avis, une fonction virtuelle dans la classe de
base ferait mieux l'affaire :
virtual void on_click() {}
Ensuite, on évite l'if, et celui qui n'a rien à faire ne le
supplante pas. C'est vrai que ça impose le nom de la fonction à
la classe dérivée, mais je ne vois pas où c'est un gros
problème. Et ça ramène le code à un modèle connu, celui du
template (ou de la méthode template).

Cependant le C++ permet des choses bien plus souples pour ce
genre de choses. Regardez les bibliothèques libsigc++ et
Boost.Signals. Avec cette dernière vous pourriez écrire ainsi
ce que vous voulez faire:

#include <boost/signal.hpp>
#include <boost/bind.hpp>

class base
{
public:
boost::signal<void ()> onclick;

void mouse_click(int a,int b)
{
onclick();
};
};


class autre : public base
{
public:
autre::autre (void)
{
onclick.connect(boost::bind(&autre::toto, this));
};

//
// une fct toto qui fait beep
//

void toto()
{
sound(200);
delay(100);
nosound();
};
};


C'est intéressant, mais en quoi est-ce qu'elle est mieux que
l'utilisation du modèle template ?

Et en passant, pour le posteur original : je sais que ce n'est
qu'un exemple, mais je ne crois pas qu'il soit une bonne idée
d'appeler une fonction comme delay dans une fonction comme
mouse_click. En supposant que les noms signifient ce qu'ils
semblent signifier, évidemment.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34