How to define a general member function pointer

前端 未结 5 923
南方客
南方客 2021-02-14 21:35

I have created a Timer class that must call a callback method when the timer has expired. Currently I have it working with normal function pointers (they are declared as void (

相关标签:
5条回答
  • 2021-02-14 21:55

    Dependencies, dependencies... yeah, sure boost is nice, so is mem_fn, but you don't need them. However, the syntax of calling member functions is evil, so a little template magic helps:

       class Callback
       {
       public:
          void operator()() { call(); };
          virtual void call() = 0;
       };
    
       class BasicCallback : public Callback
       {
          // pointer to member function
          void (*function)(void);
       public:
          BasicCallback(void(*_function)(void))
              : function( _function ) { };
          virtual void call()
          { 
              (*function)();
          };
       };   
    
       template <class AnyClass> 
       class ClassCallback : public Callback
       {
          // pointer to member function
          void (AnyClass::*function)(void);
          // pointer to object
          AnyClass* object;        
       public:
          ClassCallback(AnyClass* _object, void(AnyClass::*_function)(void))
              : object( _object ), function( _function ) { };
          virtual void call()
          { 
              (*object.*function)();
          };
       };
    

    Now you can just use Callback as a callback storing mechanism so:

    void set_callback( Callback* callback );
    set_callback( new ClassCallback<MyClass>( my_class, &MyClass::timer ) );
    

    And

    Callback* callback = new ClassCallback<MyClass>( my_class, &MyClass::timer ) );
    
    (*callback)();
    // or...
    callback->call();
    
    0 讨论(0)
  • 2021-02-14 21:56

    The best solution I have used for that same purpose was boost::signal or boost::function libraries (depending on whether you want a single callback or many of them), and boost::bind to actually register the callbacks.

    class X {
    public:
       void callback() {}
       void with_parameter( std::string const & x ) {}
    };
    int main()
    {
       X x1, x2;
       boost::function< void () > callback1;
    
       callback1 = boost::bind( &X::callback, &x1 );
       callback1(); // will call x1.callback()
    
       boost::signal< void () > multiple_callbacks;
       multiple_callbacks.connect( boost::bind( &X::callback, &x1 ) );
       multiple_callbacks.connect( boost::bind( &X::callback, &x2 ) );
       // even inject parameters:
       multiple_callbacks.connect( boost::bind( &X::with_parameter, &x1, "Hi" ) );
    
       multiple_callbacks(); // will call x1.callback(), x2.callback and x1.with_parameter("Hi") in turn
    }
    
    0 讨论(0)
  • 2021-02-14 21:57

    I'm assuming an interface like this:

    void Timer::register_callback( void(*callback)(void*user_data), void* user_data );
    
    template<typename AnyClass, (AnyClass::*Func_Value)(void)>
    void wrap_method_callback( void* class_pointer )
    {
       AnyClass*const self = reinterpret_cast<AnyClass*>(class_pointer);
       (self->*Func_Value)();
    }
    
    class A
    {
    public:
       void callback()
       { std::cout << m_i << std::endl; }
       int m_i;
    };
    
    int main ()
    {
       Timer t;
       A a = { 10 };
       t.register_callback( &wrap_method_callback<A,&A::callback>, &a );
    }
    

    I think a better solution would be to upgrade call you callback to either use boost::function or a homegrown version (like Kornel's answer). However this require real C++ developers to get involved, otherwise you are very likely to introduce bugs.

    The advantage of my solution is that it is just one template function. Not a whole lot can go wrong. One disadvantage of my solution is it may slice your class with cast to void* and back. Be careful that only AnyClass* pointers are passes as void* to the callback registration.

    0 讨论(0)
  • 2021-02-14 22:10

    boost::function looks like a perfect fit here.

    0 讨论(0)
  • 2021-02-14 22:18

    Maybe the standard mem_fun is already good enough for what you want. It's part of STL.

    0 讨论(0)
提交回复
热议问题