将函数指针传递给函数

问题描述:

如果我想将任何类的非静态成员函数作为按钮的单击函数传递,应该怎么做?可能吗 ?如果是这样,我需要做什么?例如,在哪个类(EntityToolGUI在此处)按钮被初始化后,我想将其单击操作设置为该类的非静态成员函数(EntityToolGUI类的非静态成员函数)。将函数指针传递给函数

GUIButton.h 

typedef void (*ptr2clickFunc)(void); 
class GUIButton : public GUIObject { 
    private : void (*clickFunc)(void); 
    public : void setClickFunction(ptr2clickFunc clickFunc); 
}; 

GUIButton.cpp 
void GUIButton::setClickFunction(ptr2clickFunc clickFunc) 
{ 
    this->clickFunc = clickFunc; 
} 

EntityToolGUI.h 
class EntityToolGUI { 
    public : EntityToolGUI(); 
    protected : void addAnimation(); 
} 

EntityToolGUI.cpp 
void EntityToolGUI::addAnimation() 
{ 
    cout<<"add animation"<<endl; 
} 

EntityToolGUI::EntityToolGUI() 
{ 
    .... 
    btnAddAnimation->setClickFunction(&EntityToolGUI::addAnimation); 
} 

我得到一个错误,没有匹配的函数调用GUIButton :: setClickFunction(无效(EntityToolGUI :: *)())

候选人是无效GUIButton :: setClickFunction(无效(*)() )

我该如何解决?

+0

传递指向C++方法的指针时,你需要做额外的黑客攻击。请参阅http://mdzahidh.wordpress.com/2008/07/16/pointer-to-c-class-methods-or-should-you-call-em-method-pointers/ – 2012-07-13 05:10:19

如果你想传递的obj乐趣PTR,你可以使用boost ::绑定和boost ::功能

http://www.boost.org/doc/libs/1_50_0/libs/bind/bind.html

+0

使用boost的解决方案非常优雅,我想知道上述是否可能使用std库。 – 2012-07-13 05:38:45

+0

然后使用mem_fun http:// cplusplus。com/reference/std/functional/mem_fun/ 或mem_fun_ptr http://cplusplus.com/reference/std/functional/mem_fun_ref/ 它可能有点难,但应该做的工作 – 2012-07-13 05:44:13

+0

@JeffreyChen如果你的编译器是C + +11的能力,见例如['std :: bind'](http://en.cppreference.com/w/cpp/utility/functional/bind)和['std :: function'](http://en.cppreference.com/w/CPP /实用程序/功能/功能)。 – 2012-07-13 05:48:48

不能将指向非静态成员函数的指针作为指向“常规”非成员函数的指针。您应该使静态为addAnimation,或者使ptr2clickFunc typedef a pointer to member function

请注意,调用指向成员函数的指针与调用函数指针不同,因为您必须提供将调用成员指针的实例。

+0

如果我想要怎么办?传递任何类的非静态成员函数?可能吗 ?如果是这样,我需要做什么?例如,在哪个类中按钮被初始化,我想将其单击操作设置为该类的非静态成员函数。 – 2012-07-13 05:21:11

+0

@JeffreyChen你不能创建一个能够保存任何类的成员函数的类型,但是如果这些类有一个共同的祖先,你可以存储该祖先的成员函数。当然,在这种情况下不需要,因为你可以使用虚函数而不是成员指针。 – dasblinkenlight 2012-07-13 10:32:04

addAnimation需要是静态函数。当回调函数按照您现在正在执行的方式进行设置时,类EntityTollGUI的对象不会随函数一起注册。

试试这个(C++ 11):

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

class Raiser 
{ 
public: 
    std::function<void(int)> ev1, ev2; 

    void RaiseEv1() 
    { 
     if (!ev1._Empty()) 
      ev1(44); 
    } 

    void RaiseEv2() 
    { 
     if (!ev2._Empty()) 
      ev2(66); 
    } 
}; 

class Handler 
{ 
private: 
    int id; 

    std::function<void(int)> h; 

public: 
    Handler(int newId) 
    { 
     id = newId; 

     h = [this](int i) 
     { 
      printf("Handler with id = %d captured event!\n", this->GetId()); 
     }; 
    } 

    void Hook1(Raiser & raiser) 
    { 
     raiser.ev1 = h; 
    } 

    void Hook2(Raiser & raiser) 
    { 
     raiser.ev2 = h; 
    } 

    int GetId() 
    { 
     return id; 
    } 
}; 

int main(int argc, char * argv[]) 
{ 
    Raiser raiser; 
    Handler handler1(1), handler2(2); 

    handler1.Hook1(raiser); 
    handler2.Hook2(raiser); 

    raiser.RaiseEv1(); 
    raiser.RaiseEv2(); 

    getchar(); 
} 

AFAIK,这是使用C++的事件可以获得的最多,而不使用语言扩展。

传递函数指针的大部分(正派)C代码都使用额外的void *参数来传递用户上下文到函数。这在C++中并不常见(因为存在比函数指针更好的技术),但是如果由于某种原因而使用函数指针,那么它可能是合适的。

typedef void (*ptr2clickFunc)(void*); 
class GUIButton : public GUIObject { 
    private : ptr2clickFunc clickFunc; 
    private : void * userdata; 
    public : void setClickFunction(ptr2clickFunc clickFunc, void* userdata); 
}; 

class Foo 
{ 
    static void do_foo(void * userdata) 
    { 
    Foo* thisptr = static_cast<Foo*>(userdata); 
    thisptr->foo(); 
    } 
    void foo() { ... } 
}; 

int main() 
{ 
    Foo foo; 
    GUIButton button; 
    button.setClickFunction(&Foo::do_foo, &foo); 
    button.click(); 
} 

编辑正如注意到鲍尔泰克,如果你做这个有很多,你可以提取静态函数成一个模板 - 它看起来有点像这样(含有少量errrors未经测试并可能)。

// GUIButton is as before 

// Note no static function here 
class Foo { void foo(); } 

template<typename T, void(T::*FN)() > 
void Call(void * data) 
{ 
    static_cast<T*>(data)->*FN(); 
} 

int main() 
{ 
    Foo f; 
    GUIButton button; 
    button.setClickFunction(&Call<Foo,&Foo::foo>, &f); 
    button.click(); 
} 
+0

既然你已经在使用C++,那么如果每个类都不会有do_foo方法,并且使模板不在其中, – 2012-07-14 00:03:03