studio programacion móviles keywords ejemplo descripcion desarrollo curso aplicaciones c++ function callback member

c++ - programacion - meta title seo



Ejemplos simples de devolución de llamada de miembro de clase C++ (5)

Sé que esto se ha preguntado tantas veces, y por eso es difícil buscar en el cruft y encontrar un ejemplo simple de lo que funciona.

Lo tengo, es simple y funciona para MyClass ...

#include <iostream> 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..." << endl; //Let''s pretend an event just occured owner->Callback(owner,1); } }; EventHandler* handler; MyClass::MyClass() { private_x = 5; handler->addHandler(this); } void MyClass::Callback(MyClass* instance, int x) { cout << x + instance->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); };

¿Cómo se puede reescribir así que EventHandler::addHandler() funcionará con MyClass y YourClass ? Lo siento, pero así es como funciona mi cerebro, necesito ver un ejemplo simple de lo que funciona antes de poder comprender por qué y cómo funciona. Si tiene una forma favorita de hacer que esto funcione ahora es el momento de mostrarlo, por favor marque ese código y vuelva a publicarlo.

[editar]

Fue respondida pero la respuesta fue eliminada antes de que pudiera dar la marca de verificación. La respuesta en mi caso fue una función de plantilla. Se ha cambiado AddHandler a esto ...

class EventHandler { public: template<typename T> void addHandler(T* owner) { cout << "Handler added..." << endl; //Let''s pretend an event just occured owner->Callback(owner,1); } };


Aquí hay una versión concisa que funciona con devoluciones de llamada de métodos de clase y con devoluciones de funciones regulares. En este ejemplo, para mostrar cómo se manejan los parámetros, la función de devolución de llamada toma dos parámetros: bool e int .

class Caller { template<class T> 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<std::function<void(bool,int)>> 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);

Esto restringe el código específico de C ++ 11 al método addCallback y datos privados en la clase Caller. Para mí, al menos, esto minimiza la posibilidad de cometer errores al implementarlo.


En lugar de tener métodos estáticos y pasar un puntero a la instancia de clase, podría usar la funcionalidad en el nuevo estándar C ++ 11: std::function y std::bind :

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

El método addHandler ahora acepta un argumento std::function , y este "objeto de función" no tiene valor de retorno y toma un entero como argumento.

Para vincularlo a una función específica, usa 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; }

Necesitará usar std::bind cuando agregue el controlador, ya que explícitamente necesita especificar el puntero de lo contrario implícito como argumento. Si tiene una función autónoma, no tiene que usar std::bind :

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

Tener el controlador de eventos usando std::function objects, también hace posible usar las nuevas funciones de C ++ 11 lambda :

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


Lo que quiere hacer es crear una interfaz que maneje este código y todas sus clases implementen la interfaz.

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 {

Tenga en cuenta que para que esto funcione, la función "Devolución de llamada" no es estática, lo que creo que es una mejora. Si desea que sea estático, debe hacerlo como sugiere JaredC con las plantillas.


MyClass y YourClass podrían derivarse de SomeonesClass que tiene un método de Callback abstracto (virtual). Su addHandler aceptaría objetos de tipo SomeonesClass y MyClass y YourClass puede anular la Callback de Callback para proporcionar su implementación específica del comportamiento de devolución de llamada.


Si tiene devoluciones de llamada con diferentes parámetros, puede usar plantillas de la siguiente manera:
// compilar con: g ++ -std = c ++ 11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp

#include <functional> // c++11 #include <iostream> // 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<typename T, class T2> 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(); }