9
votes

Comment définir un pointeur de fonction de membre général

J'ai créé une classe de minuterie qui doit appeler une méthode de rappel lorsque la minuterie a expiré. Actuellement, je le travaille avec des pointeurs de fonction normales (ils sont déclarés comme void (*) (void), lorsque l'événement écoulé se produit, le pointeur de fonction est appelé.

est possible de faire la même chose avec une fonction de membre qui a également le vide de signature (Anyclass :: *) (void)?

Merci Mates.

Edit: Ce code doit fonctionner sous Windows et également sur un système d'exploitation en temps réel (VXWorks) afin de ne pas utiliser de bibliothèques externes serait formidable.

EDIT2: Juste pour être sûr, ce dont j'ai besoin, c'est d'avoir une classe de minuterie qui prend une dispute au constructeur de tipe "anyclass.anmethod" sans arguments et de retourner. Je dois stocker cet argument et ce dernier en un point du code, il suffit d'exécuter la méthode pointée par cette variable. L'espoir est clair.


1 commentaires

Êtes-vous sûr que le pointeur de fonction n'est pas déclaré void (*) (vide *) . Je serais extrêmement choqué s'il n'a pas accepté un Void * comme paramètre.


5 Réponses :


4
votes

La meilleure solution que j'ai utilisée à la même usage était Boost :: Signal ou Boost :: Fonction bibliothèques (selon que vous voulez un seul rappel ou beaucoup d'entre eux), et BOOST :: LIEN Pour enregistrer les rappels.

class X {
public:
   void callback() {}
   void with_parameter( std::string const & x ) {}
};
int main()
{
   X x1, x2;
   boost::function< void () > callback1;

   callback1 = boost::bind( &X::callback, &x1 );
   callback1(); // will call x1.callback()

   boost::signal< void () > multiple_callbacks;
   multiple_callbacks.connect( boost::bind( &X::callback, &x1 ) );
   multiple_callbacks.connect( boost::bind( &X::callback, &x2 ) );
   // even inject parameters:
   multiple_callbacks.connect( boost::bind( &X::with_parameter, &x1, "Hi" ) );

   multiple_callbacks(); // will call x1.callback(), x2.callback and x1.with_parameter("Hi") in turn
}


3 commentaires

Mais ne stimule pas une bibliothèque externe?


Oui, ils ne font pas partie de la norme, mais Boost est la bibliothèque non standard la plus standard que vous trouverez.


En outre, fonction et lid- sera ajouté à la bibliothèque standard C ++ 0x (peut être déjà disponible dans std :: tr1 Espace de noms).



1
votes

Boost :: Fonction ressemble à un ajustement parfait ici.


2 commentaires

Il a dit aucune bibliothèque externe.


Oh, j'ai raté que :) Veuillez noter que Boost :: La fonction est une bibliothèque d'en-tête uniquement, donc aucune dépendance de liaison.



2
votes

Peut-être la standard MEM_FUN est déjà assez bon pour ce que vous voulez. Cela fait partie de stl.


1 commentaires

J'ai proposé de booster :: Fonction Comme je supposais que la minuterie serait une classe non modélisée qui devait conserver le rappel pour une utilisation ultérieure. Étant donné que MEM_FUN est modélisé, vous tachez la classe de la minuterie de la classe du rappel, soit sinon vous devrez envelopper le MEM_FUN dans une classe non modèles, et voici où vous finissez par mettre en œuvre Boost :: Fonctionnez vous-même ...



9
votes

Dépendances, dépendances ... Ouais, Sure Boost est sympa, mem_fn, mais vous n'en avez pas besoin. Toutefois, la syntaxe des fonctions des membres de l'appel est diabolique. Un petit modèle Magic aide:

Callback* callback = new ClassCallback<MyClass>( my_class, &MyClass::timer ) );

(*callback)();
// or...
callback->call();


5 commentaires

Ok, prenez à l'esprit que je ne comprends pas presque rien ici. C ++ n'est pas ce que j'utilise pour travailler avec, j'ai juste besoin de modifier un projet en cours d'exécution, donc je m'attends à éviter de comprendre toute cette magie. Comment puis-je exécuter le rappel? Si je viens de mettre le rappel (); Je reçois un terme n'évalue pas à une fonction prenant 0 arguments. Merci d'avance.


Et la classe BasicCallback semble être utilisée nulle part. Peut-être qu'il y a une erreur là-bas?


@Somos, basiccallback vous permet d'utiliser la même interface avec vos anciens rappels - cela ne prend pas une classe. Vous avez obtenu votre erreur car vous avez essayé de "exécuter" un pointeur, (* rappel) () serait l'appel approprié. J'ai modifié mon code un peu et ajouté une méthode explicite , peut-être que cela sera plus clair.


Merci (* rappel) () suffit pour moi. Vous vous aidez m'a sauvé une tonne d'heures. Merci beaucoup.


Oh mon Dieu. J'essayais de créer mon propre rappel pour l'enfer beaucoup de temps. Merci pour Thins, ça marche enfin



0
votes

Je suppose une interface comme celle-ci:

void Timer::register_callback( void(*callback)(void*user_data), void* user_data );

template<typename AnyClass, (AnyClass::*Func_Value)(void)>
void wrap_method_callback( void* class_pointer )
{
   AnyClass*const self = reinterpret_cast<AnyClass*>(class_pointer);
   (self->*Func_Value)();
}

class A
{
public:
   void callback()
   { std::cout << m_i << std::endl; }
   int m_i;
};

int main ()
{
   Timer t;
   A a = { 10 };
   t.register_callback( &wrap_method_callback<A,&A::callback>, &a );
}


0 commentaires