Esempi di callback di membri della class C ++ semplici

So che questo è stato chiesto così tante volte, e per questo è difficile scavare attraverso il cruft e trovare un semplice esempio di ciò che funziona.

Ho questo, è semplice e funziona per 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); }; 

Come può essere riscritto così EventHandler::addHandler() funzionerà con MyClass e YourClass . Mi dispiace ma è proprio il modo in cui funziona il mio cervello, ho bisogno di vedere un semplice esempio di ciò che funziona prima di poter capire perché / come funziona. Se hai un modo preferito per fare in modo che questo lavoro sia il momento di mostrarlo, per favore contrassegna quel codice e pubblicalo di nuovo.

[modificare]

Fu risposto ma la risposta fu cancellata prima che potessi dare il segno di spunta. La risposta nel mio caso era una funzione basata su modelli. Aggiunto addHandler a questo …

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

    Invece di avere metodi statici e passare un puntatore all’istanza della class, è ansible utilizzare la funzionalità nel nuovo standard C ++ 11: std::function e std::bind :

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

    Il metodo addHandler ora accetta un argomento std::function , e questo "object funzione" non ha valore restituito e prende un intero come argomento.

    Per associarlo a una funzione specifica, utilizzare 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; } 

    È necessario utilizzare std::bind quando si aggiunge il gestore, poiché è esplicitamente necessario specificare il puntatore implicito altrimenti come argomento. Se si dispone di una funzione indipendente, non è necessario utilizzare std::bind :

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

    Avere il gestore di eventi usa gli oggetti std::function , rende anche ansible utilizzare le nuove funzioni lambda C ++ 11:

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

    Ecco una versione concisa che funziona con i callback dei metodi di class e con le normali callback delle funzioni. In questo esempio, per mostrare come vengono gestiti i parametri, la funzione di callback accetta due parametri: bool e 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); 

    Ciò limita il codice specifico di C ++ 11 al metodo addCallback e ai dati privati ​​nella class Caller. Per me, almeno, questo riduce al minimo la possibilità di commettere errori durante l’implementazione.

    Quello che vuoi fare è creare un’interfaccia che gestisca questo codice e che tutte le tue classi implementino l’interfaccia.

     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 { 

    Si noti che per far funzionare la funzione “Callback” non è statico e credo sia un miglioramento. Se vuoi che sia statico, devi farlo come suggerisce JaredC con i modelli.

    MyClass e YourClass potrebbero entrambi essere derivati ​​da SomeonesClass che ha un metodo di Callback astratto (virtuale). addHandler accetta gli oggetti di tipo SomeonesClass e MyClass e YourClass può sovrascrivere il Callback per fornire la specifica implementazione del comportamento di callback.

    Se hai callback con parametri diversi puoi usare i template come segue:
    // compila con: 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::string str); private: std::string 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(); }