在特定对象实例上调用 C++ 函数指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/151418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:15:58  来源:igfitidea点击:

Calling a C++ function pointer on a specific object instance

c++pointersfunction

提问by fryguybob

I have a function pointer defined by:

我有一个由以下定义的函数指针:

typedef void (*EventFunction)(int nEvent);

Is there a way to handle that function with a specific instance of a C++ object?

有没有办法用 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 }
};

Edit:Orion pointed out the options that Boost offers such as:

编辑:Orion 指出了 Boost 提供的选项,例如:

boost::function<int (int)> f;
X x;
f = std::bind1st(
      std::mem_fun(&X::foo), &x);
f(5); // Call x.foo(5)

Unfortunately Boost is not an option for me. Is there some sort of "currying" function that can be written in C++ that will do this kind of wrapping of a pointer to a member function in to a normal function pointer?

不幸的是,Boost 不是我的选择。是否有某种可以用 C++ 编写的“柯里化”函数,可以将指向成员函数的指针这种包装成普通函数指针?

采纳答案by Ron Warholic

I highly recommend Don Clugston's excellent FastDelegate library. It provides all the things you'd expect of a real delegate and compiles down to a few ASM instructions in most cases. The accompanying article is a good read on member function pointers as well.

我强烈推荐 Don Clugston 出色的 FastDelegate 库。它提供了您对真实委托所期望的所有内容,并在大多数情况下编译为一些 ASM 指令。随附的文章也很好地阅读了成员函数指针。

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

回答by Orion Edwards

Run away from raw C++ function pointers, and use std::functioninstead.

远离原始 C++ 函数指针,而使用它std::function

You can use boost::functionif you are using an old compiler such as visual studio 2008 which has no support for C++11.
boost:functionand std::functionare the same thing - they pulled quite a bit of boost stuff into the std library for C++11.

boost::function如果您使用的是不支持 C++11 的旧编译器,例如 Visual Studio 2008,则可以使用。
boost:function并且std::function是同一件事 - 他们将相当多的 boost 内容拉入 C++11 的 std 库中。

Note: you may want to read the boost function documentation instead of the microsoft one as it's easier to understand

注意:您可能需要阅读 boost 函数文档而不是微软文档,因为它更容易理解

回答by David Citron

You can use function pointers to index into the vtable of a given object instance. This is called a member function pointer. Your syntax would need to change to use the ".*" and the "&::" operators:

您可以使用函数指针来索引给定对象实例的 vtable。这称为成员函数指针。您的语法需要更改以使用“.*”和“&::”运算符:

class A;
class B;
typedef void (B::*EventFunction)(int nEvent)

and then:

进而:

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 */ }
};

回答by Onorio Catenacci

You may find C++ FAQ by Marshall Clinehelpful to what you're trying to accomplish.

您可能会发现Marshall Cline 的 C++ FAQ对您要完成的工作有所帮助。

回答by Franci Penov

Read about pointers to members. To call a method on the derived class, the method has to be declared in the base class as virtual and overriden in the base class and your pointer should point to the base class method. More about pointers to virtual members.

阅读关于成员的指针。要在派生类上调用方法,必须在基类中将该方法声明为虚拟方法并在基类中重写,并且您的指针应指向基类方法。更多关于指向虚拟成员的指针

回答by Adam Rosenfield

If you're interfacing with a C library, then you can't use a class member function without using something like boost::bind. Most C libraries that take a callback function usually also allow you to pass an extra argument of your choosing (usually of type void*), which you can use to bootstrap your class, as so:

如果您要与 C 库交互,则不能使用类成员函数而不使用boost::bind. 大多数采用回调函数的 C 库通常还允许您传递您选择的额外参数(通常是 type 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
}

回答by markets

Unfortunately, the EventFunction type cannot point to a function of B, because it is not the correct type. You could make it the correct type, but that probably isn't really the solution you want:

不幸的是,EventFunction 类型不能指向 B 的函数,因为它不是正确的类型。您可以使其成为正确的类型,但这可能不是您真正想要的解决方案:

typedef void (*B::EventFunction)(int nEvent);

typedef void (*B::EventFunction)(int nEvent);

... and then everything works once you call the callback with an obhect of B. But you probably want to be able to call functions outside of B, in other classes that do other things. That is sort of the point of a callback. But now this type points to something definitely in B. More attractive solutions are:

...然后一切正常,一旦您使用 B 的对象调用回调。但是您可能希望能够调用 B 之外的函数,在执行其他操作的其他类中。这就是回调的重点。但现在这种类型指向 B 中的某些东西。更有吸引力的解决方案是:

  • Make B a base class, then override a virtual function for each other class that might be called. A then stores a pointer to B instead of a function pointer. Much cleaner.
  • If you don't want to bind the function to a specific class type, even a base class (and I wouldn't blame you), then I suggest you make the function that gets called a static function: "static void EventFrom A(int nEvent);". Then you can call it directly, without an object of B. But you probably want it to call a specific instance of B (unless B is a singleton).
  • So if you want to be able to call a specific instance of B, but be able to call non-B's, too, then you need to pass something else to your callback function so that the callback function can call the right object. Make your function a static, as above, and add a void* parameter which you will make a pointer to B.
  • 使 B 成为基类,然后为可能被调用的每个其他类覆盖一个虚函数。A 然后存储指向 B 的指针而不是函数指针。干净多了。
  • 如果您不想将函数绑定到特定的类类型,甚至是基类(我不会责怪您),那么我建议您将被称为静态函数的函数:“ static void EventFrom A(int nEvent);”。然后你可以直接调用它,而不需要 B 的对象。但你可能希望它调用 B 的特定实例(除非 B 是单例)。
  • 因此,如果您希望能够调用 B 的特定实例,但也能够调用非 B 实例,那么您需要将其他内容传递给回调函数,以便回调函数可以调用正确的对象。使您的函数成为静态函数,如上所述,并添加一个 void* 参数,您将创建一个指向 B 的指针。

In practice you see two solutions to this problem: ad hoc systems where you pass a void* and the event, and hierarchies with virtual functions in a base class, like windowing systems

在实践中,您会看到此问题的两种解决方案:传递 void* 和事件的临时系统,以及基类中具有虚函数的层次结构,如窗口系统

回答by Corey Ross

You mention that boost isn't an option for you, but do you have TR1 available to you?

您提到提升不是您的选择,但是您有可用的 TR1 吗?

TR1 offers function, bind, and mem_fn objects based on the boost library, and you may already have it bundled with your compiler. It isn't standard yet, but at least two compilers that I've used recently have had it.

TR1 提供基于 boost 库的函数、绑定和 mem_fn 对象,您可能已经将它与编译器捆绑在一起。它还不是标准的,但我最近使用的至少两个编译器已经有了它。

http://en.wikipedia.org/wiki/Technical_Report_1
http://msdn.microsoft.com/en-us/library/bb982702.aspx

http://en.wikipedia.org/wiki/Technical_Report_1
http://msdn.microsoft.com/en-us/library/bb982702.aspx

回答by KPexEA

I have a set of classes for this exact thing that I use in my c++ framework.

对于我在我的 C++ 框架中使用的这个确切的东西,我有一组类。

http://code.google.com/p/kgui/source/browse/trunk/kgui.h

http://code.google.com/p/kgui/source/browse/trunk/kgui.h

How I handle it is each class function that can be used as a callback needs a static function that binds the object type to it. I have a set of macros that do it automatically. It makes a static function with the same name except with a "CB_" prefix and an extra first parameter which is the class object pointer.

我如何处理它是每个可以用作回调的类函数都需要一个将对象类型绑定到它的静态函数。我有一组自动执行的宏。它创建了一个同名的静态函数,除了带有“CB_”前缀和一个额外的第一个参数,即类对象指针。

Checkout the Class types kGUICallBack and various template versions thereof for handling different parameters combinations.

检查类类型 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);}

回答by shoosh

It's somewhat unclear what you're trying to accomplish here. what is clear is that function pointers is not the way.

有点不清楚您要在这里完成什么。很明显,函数指针不是方法。

maybe what you're looking for is pointer to method.

也许您正在寻找的是指向方法的指针。