简体   繁体   English

C ++:成员函数地址(函数指针)

[英]C++: member function address (function pointers)

I have a class X which has this method: 我有一个类X有这个方法:

void setRxHandler(void (*h)(int));

And I want to pass to it a member function that exists in instances of class Y . 我想传递一个存在于Y类实例中的成员函数。

void comm_rxHandler(int status);

I tried the following: 我尝试了以下方法:

x.setRxHandler(comm_rxHandler) 

But it get the following compile error (I'm using Qt): 但它得到以下编译错误(我正在使用Qt):

error: no matching function for call to 'X::setRxHandler(< unresolved overloaded function type>)' 错误:没有用于调用'X :: setRxHandler(<unresolved overloaded function type>)的匹配函数

So, how can I do that? 那么,我该怎么做呢?

I noticed if I declare comm_rxHandler (class Y) as static, I have no errors. 我注意到如果我将comm_rxHandler(类Y)声明为静态,我没有错误。 But I want comm_rxHandler as a non-static method. 但我想将comm_rxHandler作为非静态方法。 Also I want setRxHandler method (class X) to be generic and not class-specific. 另外,我希望setRxHandler方法(类X)是通用的,而不是特定于类。 So I can't declare that method as: 所以我不能将该方法声明为:

setRxHandler(void (Y::*h)(int))

How to do that? 怎么做? Can you help me on this? 你能帮帮我吗?

Thanks! 谢谢!

C++ doesn't support bound methods . C ++不支持绑定方法 To invoke a member function through a function pointer, you need to have two things: an instance of the class and the function pointer. 要通过函数指针调用成员函数,您需要有两件事:类的实例和函数指针。

So setRxHandler(void (Y::*h)(int)) is almost correct. 所以setRxHandler(void (Y::*h)(int))几乎是正确的。 You need to declare it as: 您需要将其声明为:

void setRxHandler(Y*, void (Y::*h)(int));

To invoke setRxHandler() , you need to pass it arguments as follows: 要调用setRxHandler() ,需要按如下方式传递参数:

Y y;
setRxHandler(&y, &Y::comm_rxHandler);

In the setRxHandler() method, you can invoke the function pointer using this syntax: setRxHandler()方法中,您可以使用以下语法调用函数指针:

void setRxHandler ( Y* y, void (Y::*h)(int) )
{
    // ...
    (y->*h)(0);
    // ...
}

To make generic, you need to abstract the Y parameter away, but this is difficult to get right. 要制作通用,您需要抽象Y参数,但这很难做到。 Check out Boost.Function for an existing implementation that supports this use case, and many more. 查看Boost.Function以获取支持此用例的现有实现,以及更多内容。

Change your callback to this: 将您的回调更改为:

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

Then you can use binders: 然后你可以使用粘合剂:

setRxHandler( std::bind(&class_name::comm_rxHandler, obj) );

( std::function and std::bind are part of the upcomming next version of the C++ standard. It's quite likely your compiler already comes with them. If not, they might live in namespace std::tr1 . If all else fails, you will find them at boost - which is where they were invented - as boost::function and boost::bind .) std::functionstd::bind是升级下一版C ++标准的一部分。很可能你的编译器已经附带它们。如果没有,它们可能存在于命名空间std::tr1 。如果所有其他都失败了,你会发现它们在boost - 这是它们被发明的地方 - 作为boost::functionboost::bind 。)

You can, however, also pass non-member or static functions to setRxHandler , as well as function objects (which is the result of std::bind ). 但是,您也可以将非成员函数或静态函数传递给setRxHandler ,以及函数对象(这是std::bind的结果)。

If your compiler already supports lambda functions (also part of the next standard, but already supported by, eg, recent versions of GCC and VC), you can also use one of those: 如果您的编译器已经支持lambda函数(也是下一个标准的一部分,但已经受到例如GCC和VC的最新版本的支持),您还可以使用其中一个:

setRxHandler( [](){obj.comm_rxHandler();} );

As it is now, the setRxHandler prototype takes a pointer to a function that doesn't return anything and takes an int . 就像现在一样, setRxHandler原型获取一个指向函数的指针,该函数不返回任何内容并采用int As you have noticed, this won't work with member functions because they can't be called like a normal function (you have to handle the this pointer as well, which means having an instance of that class to call the method on). 正如您所注意到的,这不适用于成员函数,因为它们不能像普通函数一样被调用(您还必须处理this指针,这意味着要使用该类的实例来调用该方法)。

To make it both work with member functions and non-specific ( generic ), you have to either make a base class and have all classes you want to use setRxHandler with derive from that class: 要使它既可以使用成员函数又可以使用非特定( 泛型 ),您必须创建一个基类,并且要使用setRxHandler并使用派生自该类的所有类:

class Base { ... };
class Derived : public Base { ... };

// then for the prototype
void setRxHandler(void (Base::*h)(int)) { ... }
// and you can use setRxHandler for all types that derive from Base, which gives you more control than the second option, which is:

or use templates: 或使用模板:

template<typename T>
void setRxHandler(void (T::*h)(int)) { ... }

With the template option, you really have no control over what class will be used with setRxHandler (excluding RTTI), which can be exactly what you want. 使用模板选项,您实际上无法控制将与setRxHandler (不包括RTTI)一起使用的类,这可能正是您想要的。

You can either make a base class for Y and use that (to avoid being "class specific"), or use templates: 您可以为Y创建基类并使用它(以避免“特定于类”),或使用模板:

template <class T>
setRxHandler(void (T::*h)(int));

But then this may raise questions of how to use the member function (you tell us if it does). 但是,这可能会引发如何使用成员函数的问题(如果有的话,请告诉我们)。

As others have already mentioned, C++ does not provide this functionality. 正如其他人已经提到的,C ++不提供此功能。

Another option you could use is libsigc++ which is widely used in gtkmm, see this example in their tutorial for instance on how to pass pointers to member-functions. 你可以使用另一种选择是libsigc ++被广泛应用于gtkmm的,看到这个例子中就如何通过指向成员函数教程实例。 Your example could look something like: 您的示例可能类似于:

// sigc::slot<void, int> is a 'slot' to hold a function with return type void 
// and 1 int argument.
void setRxHandler(sigc::slot<void, int> slot);
void comm_rxHandler(int status);

//sigc::mem_fun() can convert a member function to a function slot.
x.setRxHandler(sigc::mem_fun(*this, &X::comm_rxHandler));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM