2009-02-05 54 views
3

我需要将一个方法绑定到一个函数回调中,除非此代码段不合法,如demote-boostfunction-to-a-plain-function-pointer中所述。来自绑定方法的原始函数指针

获取此行为的最简单方法是什么?

struct C { 
void m(int x) { 
    (void) x; 
    _asm int 3; 
}}; 

typedef void (*cb_t)(int); 
int main() { 
    C c; 
    boost::function<void (int x)> cb = boost::bind(&C::m, &c, _1); 
    cb_t raw_cb = *cb.target<cb_t>(); //null dereference 
    raw_cb(1); 
    return 0; 
} 

回答

2

你可以让你自己的类和boost绑定函数做同样的事情。所有类所要做的就是接受函数类型和指向包含该函数的对象的指针。例如,这是一个无效的回报和无效PARAM代表:

template<typename owner> 
class VoidDelegate : public IDelegate 
{ 
public: 
    VoidDelegate(void (owner::*aFunc)(void), owner* aOwner) 
    { 
     mFunction = aFunc; 
     mOwner = aOwner; 
    } 
    ~VoidDelegate(void) 
    {} 
    void Invoke(void) 
    { 
     if(mFunction != 0) 
     { 
     (mOwner->*mFunction)(); 
     } 
    } 

private: 
    void (owner::*mFunction)(void); 
    owner* mOwner; 
}; 

用法:现在

,因为VoidDelegate<C>是一个类型,具有这些集合可能是不实际的,因为什么,如果该列表是否包含B类的函数呢?它不能。

这是多态性发挥作用的地方。你可以创建一个接口IDelegate,其中有一个函数调用:

class IDelegate 
{ 
    virtual ~IDelegate(void) { } 
    virtual void Invoke(void) = 0; 
} 

如果VoidDelegate<T>工具IDelegate你可以有IDelegates的集合,因此有回调,以在不同的类类型的方法。

2

要么你可以推说绑定参数到一个全局变量,创建一个静态函数,可以拿起值并调用它的函数,或者你将不得不在产生每个实例功能飞 - 这将涉及某种即时代码生成一个存根函数堆上有一个静态局部变量设置为您想要的值,然后调用它的功能。

第一种方法简单易懂,但根本不是线程安全的或可重入的。第二个版本是混乱和困难的,但是如果做得对,则是线程安全的和可重入的。

编辑:我刚刚发现,ATL使用代码生成技术来做到这一点 - 它们会动态生成think,设置this指针和其他数据,然后跳转到回调函数。 Here's a CodeProject article,它解释了这是如何工作的,并可能让你知道如何自己做。特别看最后一个样本(程序77)。

请注意,由于文章写了DEP已经存在,你需要使用VirtualAllocPAGE_EXECUTE_READWRITE来获得一块内存,你可以分配你的thunk并执行它们。

+0

动态代码gen肯定太复杂。寻找尽可能简单。 – 2009-02-05 15:55:17

+0

第一种方法是我所做的,看到我的回复..就是你在说什么? – 2009-02-05 15:55:50

+0

我想它会是,但是我想我无论如何都会把它扔出去。 – Eclipse 2009-02-05 16:09:35

0

我现在通过将C转换为单例,将C :: m分解为C :: m_Impl,并声明转发给单例实例的静态C :: m(int)。谈谈黑客。

1
#include <iostream> 
typedef void(*callback_t)(int); 

template< typename Class, void (Class::*Method_Pointer)(void) > 
void wrapper(int class_pointer) 
{ 
    Class * const self = (Class*)(void*)class_pointer; 
    (self->*Method_Pointer)(); 
} 

class A 
{ 
public: 
    int m_i; 
    void callback() 
    { std::cout << "callback: " << m_i << std::endl; } 
}; 

int main() 
{ 
    A a = { 10 }; 
    callback_t cb = &wrapper<A,&A::callback>; 
    cb((int)(void*)&a); 
}