【问题标题】:Passing a function pointer to a function将函数指针传递给函数
【发布时间】:2012-07-13 05:07:34
【问题描述】:

如果我想将任何类的非静态成员函数作为按钮的点击函数传递怎么办?可能吗 ?如果是这样,我需要做什么?例如,在哪个类(此处为 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(void (EntityToolGUI::*)()) 的匹配函数调用

candidate is void GUIButton::setClickFunction(void (*)())

我该如何解决这个问题?

【问题讨论】:

标签: c++ pointers


【解决方案1】:

大多数(体面的)传递函数指针的 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();
}

编辑 正如 Bartek 所指出的,如果您经常这样做,您可以将静态函数提取到模板中 - 它看起来有点像这样(未经测试,可能有一些小错误)。

// 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();
}

【讨论】:

  • 既然你已经在使用c++,那么最好每个类都没有do_foo方法,并用它制作模板
【解决方案2】:

如果你想传递 obj fun ptr 你可以使用 boost::bind 和 boost::function

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

【讨论】:

【解决方案3】:

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

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

【讨论】:

  • 如果我想传递任何类的非静态成员函数怎么办?可能吗 ?如果是这样,我需要做什么?例如,按钮在哪个类中初始化,我想将其单击操作设置为该类的非静态成员函数。
  • @JeffreyChen 您不能创建能够保存任何类的成员函数的类型,但如果这些类有一个共同的祖先,您可以存储该祖先的成员函数。当然在这种情况下就没有必要了,因为你可以使用虚函数而不是成员指针。
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    试试这个(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++ 中获得的最多事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      • 1970-01-01
      • 2016-11-07
      • 2013-02-15
      相关资源
      最近更新 更多