题
我有一个功能的指定义:
typedef void (*EventFunction)(int nEvent);
有没有一种方法,以处理功能与一个具体实例的C++的对象?
class A
{
private:
EventFunction handler;
public:
void SetEvent(EventFunction func) { handler = func; }
void EventOne() { handler(1); }
};
class B
{
private:
A a;
public:
B() { a.SetEvent(EventFromA); } // What do I do here?
void EventFromA(int nEvent) { // do stuff }
};
编辑: 猎户座指出的选项,促进提供诸如:
boost::function<int (int)> f;
X x;
f = std::bind1st(
std::mem_fun(&X::foo), &x);
f(5); // Call x.foo(5)
不幸的是提高不是一个选项我。是有某种形式的"扩充"功能,可以用C++编写即将做这种包裹的一个指向一个成员能在一个正常功能的指针?
解决方案
我强烈推荐Don Clugston出色的FastDelegate库。它提供了您对真实代表所期望的所有内容,并在大多数情况下编译为一些ASM指令。随附的文章也很好地阅读了成员函数指针。
其他提示
您可以使用函数指针索引到给定对象实例的vtable。这称为成员函数指针。您的语法需要更改为使用“。*”和“&amp; ::”操作符:
class A;
class B;
typedef void (B::*EventFunction)(int nEvent)
然后:
class A
{
private:
EventFunction handler;
public:
void SetEvent(EventFunction func) { handler = func; }
void EventOne(B* delegate) { ((*delegate).*handler)(1); } // note: ".*"
};
class B
{
private:
A a;
public:
B() { a.SetEvent(&B::EventFromA); } // note: "&::"
void EventFromA(int nEvent) { /* do stuff */ }
};
远离原始C ++函数指针,并使用 std: :功能
。
您可以使用 boost如果您使用的是不支持C ++ 11的Visual Studio 2008等旧编译器,请执行:: function
boost:function
和 std :: function
是一回事 - 它们为C ++ 11的std库提供了相当多的增强功能。
注意:您可能希望阅读boost函数文档而不是microsoft文档,因为它更容易理解
您可以找到 Marshall Cline的C ++常见问题解答,到你想要完成的事情。
如果您正在与C库接口,那么您不能使用类成员函数而不使用 boost :: bind
之类的东西。大多数采用回调函数的C库通常也允许您传递一个您选择的额外参数(通常是 void *
类型),您可以使用它来引导您的类,如下所示:
class C
{
public:
int Method1(void) { return 3; }
int Method2(void) { return x; }
int x;
};
// This structure will hold a thunk to
struct CCallback
{
C *obj; // Instance to callback on
int (C::*callback)(void); // Class callback method, taking no arguments and returning int
};
int CBootstrapper(CCallback *pThunk)
{
// Call the thunk
return ((pThunk->obj) ->* (pThunk->callback))( /* args go here */ );
}
void DoIt(C *obj, int (C::*callback)(void))
{
// foobar() is some C library function that takes a function which takes no arguments and returns int, and it also takes a void*, and we can't change it
struct CCallback thunk = {obj, callback};
foobar(&CBootstrapper, &thunk);
}
int main(void)
{
C c;
DoIt(&c, &C::Method1); // Essentially calls foobar() with a callback of C::Method1 on c
DoIt(&c, &C::Method2); // Ditto for C::Method2
}
不幸的是,EventFunction类型不能指向一个功能B,因为这是不正确的类型。你可以做正确的类型,但这可能不是真正的解决方案,你想:
typedef void (*B::EventFunction)(int nEvent);
...然后一切工作一旦你打电话回调一个obhect B。但是你可能想要能够调用的功能外,在其他类做其他的事情。这样的点回调。但现在这种类型点东西肯定在B。更具吸引力的解决方案是:
- B一个基类,然后将复盖一个虚拟的功能用于其他各类可能被称为。一个然后存储指向B,而不是一个功能的指针。干净多了。
- 如果你不要将此函数的一个特定的类型,甚至一个基类(和我不会怪你的),那么我建议你使的功能,被称为静态功能:"
static void EventFrom A(int nEvent);
".然后你可以叫它直接,没有一个目的,B。但是你可能想要呼叫一个具体实例B(除非B是一个单独的). - 所以如果你想要能够调用的一个具体实例B中,但是能够调用非B、太,那么你需要过别的东西给你回调功能,以便回呼功能可以叫正确的对象。让你的功能有静态的,如上所述,并添加一个void*参数,你将做一个指向B。
在实践中,你看到两个解决这个问题:特设系统在哪里你通过一void*和事件和层次结构与的虚拟的功能在基类的,像窗口系统
你提到升力不适合你,但你有TR1吗?
TR1提供基于boost库的函数,绑定和mem_fn对象,您可能已将它与编译器捆绑在一起。它还不是标准的,但我最近使用过的至少两个编译器都有它。
http://en.wikipedia.org/wiki/Technical_Report_1
http://msdn.microsoft.com/en-us/library/bb982702。 aspx
目前还不清楚你要在这里完成什么。很明显,函数指针不是这样的。
也许您正在寻找的是指向方法的指针。
我有一组用于我在c ++框架中使用的确切内容的类。
http://code.google.com/p /kgui/source/browse/trunk/kgui.h
我如何处理它是每个可用作回调的类函数需要一个将对象类型绑定到它的静态函数。我有一组自动执行此操作的宏。除了使用“CB_”之外,它创建一个具有相同名称的静态函数。前缀和额外的第一个参数,它是类对象指针。
查看类型kGUICallBack及其各种模板版本,以处理不同的参数组合。
#define CALLBACKGLUE(classname , func) static void CB_ ## func(void *obj) {static_cast< classname *>(obj)->func();}
#define CALLBACKGLUEPTR(classname , func, type) static void CB_ ## func(void *obj,type *name) {static_cast< classname *>(obj)->func(name);}
#define CALLBACKGLUEPTRPTR(classname , func, type,type2) static void CB_ ## func(void *obj,type *name,type2 *name2) {static_cast< classname *>(obj)->func(name,name2);}
#define CALLBACKGLUEPTRPTRPTR(classname , func, type,type2,type3) static void CB_ ## func(void *obj,type *name,type2 *name2,type3 *name3) {static_cast< classname *>(obj)->func(name,name2,name3);}
#define CALLBACKGLUEVAL(classname , func, type) static void CB_ ## func(void *obj,type val) {static_cast< classname *>(obj)->func(val);}