Exemples simples de rappel de classe C ++

Je sais que cela a été demandé à maintes resockets, et à cause de cela, il est difficile de fouiller dans le vide et de trouver un exemple simple de ce qui fonctionne.

J’ai ça, c’est simple et ça marche pour MyClass

 #include  using std::cout; using std::endl; class MyClass { public: MyClass(); static void Callback(MyClass* instance, int x); private: int private_x; }; class EventHandler { public: void addHandler(MyClass* owner) { cout << "Handler added..." <Callback(owner,1); } }; EventHandler* handler; MyClass::MyClass() { private_x = 5; handler->addHandler(this); } void MyClass::Callback(MyClass* instance, int x) { cout <private_x << endl; } int main(int argc, char** argv) { handler = new EventHandler(); MyClass* myClass = new MyClass(); } class YourClass { public: YourClass(); static void Callback(YourClass* instance, int x); }; 

Comment cela peut-il être réécrit pour que EventHandler::addHandler() fonctionne avec MyClass et YourClass . Je suis désolé mais c’est juste la façon dont fonctionne mon cerveau, j’ai besoin de voir un exemple simple de ce qui fonctionne avant que je puisse comprendre pourquoi et comment cela fonctionne. Si vous avez le moyen préféré de faire en sorte que ce travail soit le moment de le montrer, veuillez baliser ce code et le publier.

[modifier]

Il a été répondu mais la réponse a été supprimée avant que je puisse donner la coche. La réponse dans mon cas était une fonction basée sur des modèles. Changement de addHandler pour cela …

 class EventHandler { public: template void addHandler(T* owner) { cout << "Handler added..." <Callback(owner,1); } }; 

    Au lieu d’avoir des méthodes statiques et de faire passer un pointeur sur l’instance de la classe, vous pouvez utiliser les fonctionnalités du nouveau standard C ++ 11: std::function et std::bind :

     #include  class EventHandler { public: void addHandler(std::function callback) { cout << "Handler added..." << endl; // Let's pretend an event just occured callback(1); } }; 

    La méthode addHandler accepte désormais un argument std::function , et cet "object function" n'a pas de valeur de retour et prend un entier comme argument.

    Pour le lier à une fonction spécifique, vous utilisez std::bind :

     class MyClass { public: MyClass(); // Note: No longer marked `static`, and only takes the actual argument void Callback(int x); private: int private_x; }; MyClass::MyClass() { using namespace std::placeholders; // for `_1` private_x = 5; handler->addHandler(std::bind(&MyClass::Callback, this, _1)); } void MyClass::Callback(int x) { // No longer needs an explicit `instance` argument, // as `this` is set up properly cout << x + private_x << endl; } 

    Vous devez utiliser std::bind lors de l'ajout du gestionnaire, car vous devez explicitement spécifier le pointeur implicite sous forme d'argument. Si vous avez une fonction autonome, vous n'avez pas besoin d'utiliser std::bind :

     void freeStandingCallback(int x) { // ... } int main() { // ... handler->addHandler(freeStandingCallback); } 

    Avoir le gestionnaire d'événements utilise les objects std::function , permet également d'utiliser les nouvelles fonctions lambda C ++ 11:

     handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; }); 

    Voici une version concise qui fonctionne avec les rappels de méthodes de classe et avec des rappels de fonctions réguliers. Dans cet exemple, pour montrer comment les parameters sont gérés, la fonction de rappel prend deux parameters: bool et int .

     class Caller { template void addCallback(T* const object, void(T::* const mf)(bool,int)) { using namespace std::placeholders; callbacks_.emplace_back(std::bind(mf, object, _1, _2)); } void addCallback(void(* const fun)(bool,int)) { callbacks_.emplace_back(fun); } void callCallbacks(bool firstval, int secondval) { for (const auto& cb : callbacks_) cb(firstval, secondval); } private: std::vector> callbacks_; } class Callee { void MyFunction(bool,int); } //then, somewhere in Callee, to add the callback, given a pointer to Caller `ptr` ptr->addCallback(this, &Callee::MyFunction); //or to add a call back to a regular function ptr->addCallback(&MyRegularFunction); 

    Cela restreint le code spécifique à C ++ 11 à la méthode addCallback et aux données privées de la classe Caller. Pour moi, au moins, cela minimise le risque de commettre des erreurs lors de sa mise en œuvre.

    Ce que vous voulez faire, c’est créer une interface qui gère ce code et toutes vos classes implémentent l’interface.

     class IEventListener{ public: void OnEvent(int x) = 0; // renamed Callback to OnEvent removed the instance, you can add it back if you want. }; class MyClass :public IEventListener { ... void OnEvent(int x); //typically such a function is NOT static. This wont work if it is static. }; class YourClass :public IEventListener { 

    Notez que pour que cela fonctionne, la fonction “Rappel” n’est pas statique, ce qui, à mon avis, constitue une amélioration. Si vous voulez que ce soit statique, vous devez le faire comme le suggère JaredC avec les modèles.

    MyClass et YourClass peuvent tous deux être dérivés de SomeonesClass qui possède une SomeonesClass de SomeonesClass abstraite (virtuelle). Votre addHandler accepte les objects de type SomeonesClass et MyClass et YourClass peuvent remplacer Callback pour fournir leur implémentation spécifique du comportement de rappel.

    Si vous avez des rappels avec des parameters différents, vous pouvez utiliser les modèles comme suit:
    // comstack avec: g ++ -std = c ++ 11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp

     #include  // c++11 #include  // due to: cout using std::cout; using std::endl; class MyClass { public: MyClass(); static void Callback(MyClass* instance, int x); private: int private_x; }; class OtherClass { public: OtherClass(); static void Callback(OtherClass* instance, std::ssortingng str); private: std::ssortingng private_str; }; class EventHandler { public: template void addHandler(T* owner, T2 arg2) { cout << "\nHandler added..." << endl; //Let's pretend an event just occured owner->Callback(owner, arg2); } }; MyClass::MyClass() { EventHandler* handler; private_x = 4; handler->addHandler(this, private_x); } OtherClass::OtherClass() { EventHandler* handler; private_str = "moh "; handler->addHandler(this, private_str ); } void MyClass::Callback(MyClass* instance, int x) { cout << " MyClass::Callback(MyClass* instance, int x) ==> " << 6 + x + instance->private_x << endl; } void OtherClass::Callback(OtherClass* instance, std::string private_str) { cout << " OtherClass::Callback(OtherClass* instance, std::string private_str) ==> " << " Hello " << instance->private_str << endl; } int main(int argc, char** argv) { EventHandler* handler; handler = new EventHandler(); MyClass* myClass = new MyClass(); OtherClass* myOtherClass = new OtherClass(); }