Простой пример обратного вызова члена класса C++



Я знаю, что это было задано так много раз, и из-за этого трудно копаться в крафт и найти простой пример того, что работает.



у меня есть, это просто и это работает для 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);
};


как это можно переписать так EventHandler::addHandler() С MyClass и YourClass. Мне жаль, но это просто так работает мой мозг, мне нужно увидеть простой пример того, что работает, прежде чем я смогу понять, почему/как это работает. Если у вас есть любимый способ сделать эту работу сейчас самое время, чтобы показать его, пожалуйста, разметить этот код и отправить его обратно.



[edit]



это был ответ, но ответ был удален, прежде чем я мог дать галочку.
Ответ в моем случае был шаблонной функцией. Изменен addHandler для этого...



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);
}
};
530   6  

6 ответов:

вместо того, чтобы иметь статические методы и передавать указатель на экземпляр класса, вы можете использовать функциональность в новом стандарте C++11:std::function и 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);
        }
};

The addHandler метод теперь принимает std::function аргумент, и этот "объект функции" не имеет возвращаемого значения и принимает целое число в качестве аргумента.

чтобы привязать его к определенной функции, вы используете 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;
}

вы должны использовать std::bind при добавлении обработчика, как вы явно должны указать в противном случае неявный this указатель в качестве аргумента. Если у вас есть автономная функция, вам не нужно использовать std::bind:

void freeStandingCallback(int x)
{
    // ...
}

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

имея обработчик событий использовать std::function объекты, также позволяет использовать новый C++11 лямбда-функции:

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

вот краткая версия, которая работает с обратными вызовами метода класса и с регулярными обратными вызовами функций. В этом примере, чтобы показать, как обрабатываются параметры, функция обратного вызова принимает два параметра: bool и 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);

это ограничивает специфичный для C++11 код методом addCallback и частными данными в вызывающем классе. Для меня, по крайней мере, это уменьшает вероятность ошибок при его реализации.

что вы хотите сделать, это интерфейс, который обрабатывает этот код и все ваши классы реализуют интерфейс.

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
{

обратите внимание, что для этой работы функция "обратного вызова" не является статической, которая Я считаю улучшение. Если вы хотите, чтобы он был статическим, вам нужно сделать это, как предлагает JaredC с шаблонами.

MyClass и YourClass оба могут быть получены из SomeonesClass который имеет абстрактный (виртуальный) Callback метод. Ваш addHandler принимал бы объекты типа SomeonesClass и MyClass и YourClass можно переопределить Callback чтобы обеспечить их конкретную реализацию поведения обратного вызова.

полный рабочий пример из кода выше.... для C++11:

#include <stdlib.h>
#include <stdio.h>
#include <functional>

#if __cplusplus <= 199711L
  #error This file needs at least a C++11 compliant compiler, try using:
  #error    $ g++ -std=c++11 ..
#endif

using namespace std;

class EventHandler {
    public:
        void addHandler(std::function<void(int)> callback) {
            printf("\nHandler added...");
            // Let's pretend an event just occured
            callback(1);
        }
};


class MyClass
{
    public:
        MyClass(int);
        // Note: No longer marked `static`, and only takes the actual argument
        void Callback(int x);

    private:
        EventHandler *pHandler;
        int private_x;
};

MyClass::MyClass(int value) {
    using namespace std::placeholders; // for `_1`

    pHandler = new EventHandler();
    private_x = value;
    pHandler->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
    printf("\nResult:%d\n\n", (x+private_x));
}

// Main method
int main(int argc, char const *argv[]) {

    printf("\nCompiler:%ld\n", __cplusplus);
    new MyClass(5);
    return 0;
}


// where  is your .cpp file name... this is the command used:
// g++ -std=c++11 -Wall -o  .cpp
// chmod 700 
// ./

вывод должен быть:

Compiler:201103

Handler added...
Result:6

Если у вас есть обратные вызовы с различными параметрами вы можете использовать шаблоны следующим образом:
// compile with: 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();
}

Comments

    Ничего не найдено.