C ++ система обратного вызова.Указатели на функции-члены - PullRequest
0 голосов
/ 22 октября 2010

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

Как я могу реализовать такую ​​вещь

template<class T> class A{

   void (T::*callBackFunction)(int);

   public:
       void addCallBack(void (T::*callBackFunction)(int)){
            void (T::*callBackFunction)(int) = &callBackFunction;
       }

       void performCallBack(){ //I want this to activate the specified function in class B
            callBackFunction(3);
       }
};





Class B{

   A<B> a1;
   A<B> a2;

   B(){
       a1.addCallBack(&a1CallBack);
       a2.addCallBack(&a2CallBack);
   }

   void a1CallBack(int i){
       // do stuff
   }

   void a2CallBack(int i){
       // do stuff
   }
};

Ответы [ 4 ]

3 голосов
/ 22 октября 2010

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

class BaseCB{
public:
  virtual void operator()(int x)=0;
};

template<class ClassT>
class CCallback : public BaseCB {
public:
  typedef void(ClassT::* FuncT)(int);
  FuncT _fn;
  ClassT* _c;
  CCallback(ClassT* c, FuncT fn):_fn(fn),_c(c){}
  void operator()(int x){
    return (_c->*_fn)(x);
  }
};

class B {
public:
  BaseCB* a;
  void invokecb(int n){
    (*a)(n);
  }
};

class C {
  B b;
public:
  C(){
    b.a = new CCallback<C>(this,&C::cb);
    b.invokecb(3);
  };
  void cb(int n)
  {
    cout << n;
  }
};

C c; // create an instance of c and test the cb mechanism
1 голос
/ 22 октября 2010

Вам нужна ссылка (или указатель) на объект, для которого вы хотите вызвать метод.

Я бы предложил создать базовый класс шаблона (параметры шаблона - это возвращаемое значение и параметры функции) и производный класс шаблона (все параметры базового шаблона, а также тип объекта). Производный класс содержит ссылку на объект и указатель на функцию-член.

EDIT:

Может быть, что-то вроде этого (не проверено):

template < typename R, typename T1 >
class CbBase
{
  public:
    virtual ~CbBase(){}
    virtual R call( T1 t1 ) = 0;
};

template < typename O, typename R, typename T1 >
class MemFunPtrCb : public CbBase< R, T1 >
{
  public:
    MemFunPtrCb( O &obj_, R (O::*memFcPtr_)( T1 t1 ) ) :
      obj( obj_ ),
      memFcPtr( memFcPtr_ ),
    {
    }

    virtual R call( T1 t1 )
    {
        obj.memFcPtr( t1 );
    }

  private:
    O &obj;
    R (O::*memFcPtr)( T1 t1 );
};

Этот пример отсутствует:

  • функция для создания объекта MemFuncPtrCb, эта функция должна получить ссылку на объект и функцию-член и вернуть shared_ptr в соответствующий базовый класс

  • * 1018 определения типов *

1 голос
/ 22 октября 2010

Указатели на функцию-член требуют указателя на экземпляр в качестве первого параметра. Прочтите это . Общий способ сделать это состоит в том, чтобы функция обратного вызова приняла дополнительный параметр (обычно void *), который может представлять дополнительную информацию или контекст для обработчика обратного вызова. Это может быть указатель на объект, которому будет делегирован обратный вызов.

0 голосов
/ 22 октября 2010

Если вам действительно нужна функция обратного вызова, которая принимает int в качестве параметра и возвращает void, вы можете использовать boost :: function.

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>

struct A
{
   typedef boost::function1<int, void> func_type;
   func_type func;

   explicit A( func_type func_ ) :
      func( func_ )
   {
   }

   void call( int x )
   {
       func(x);
   }
};

struct B
{
   int myVal;
   explicit B(int val ) : myVal( val ) {}

   void mycall(int x)
    {
       std::cout << (myVal + x) << std::endl;
    }
};

int main()
{
   B b(5);
   A a( boost::bind( &B::mycall, b, _1 ) );
   a.call( 3 );
}

и, если повезет, напечатает 8.

...