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

时间:2011-07-30 16:52:39

标签: c++ function-pointers

我有一个类X ,它有这个方法:

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

我想传递一个存在于 Y类实例中的成员函数。

void comm_rxHandler(int status);

我尝试了以下内容:

x.setRxHandler(comm_rxHandler) 

但它得到以下编译错误(我正在使用Qt):

  

错误:没有匹配的调用函数   'X :: setRxHandler(< unresolved overloaded function type>)'

那么,我该怎么做?

我注意到如果我将comm_rxHandler(类Y)声明为静态,我没有错误。但我想将comm_rxHandler作为非静态方法。另外,我希望setRxHandler方法(类X)是通用的,而不是特定于类。所以我不能将该方法声明为:

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

怎么做?你能帮我解决这个问题吗?

谢谢!

5 个答案:

答案 0 :(得分:1)

C ++不支持bound methods。要通过函数指针调用成员函数,您需要有两件事:类的实例和函数指针。

所以setRxHandler(void (Y::*h)(int))几乎是正确的。您需要将其声明为:

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

要调用setRxHandler(),您需要按如下方式传递参数:

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

setRxHandler()方法中,您可以使用以下语法调用函数指针:

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

要制作通用,您需要抽象Y参数,但这很难做到。查看Boost.Function以获取支持此用例的现有实现,以及更多内容。

答案 1 :(得分:1)

将您的回调更改为:

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

然后你可以使用粘合剂:

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

std::functionstd::bind是升级下一版C ++标准的一部分。很可能你的编译器已经附带它们。如果没有,它们可能存在于命名空间std::tr1中如果所有其他方法都失败了,你会在boost找到它们 - 这就是它们被发明的地方 - boost::functionboost::bind。)

但是,您也可以将非成员函数或静态函数传递给setRxHandler,以及函数对象(这是std::bind的结果)。

如果您的编译器已经支持lambda函数(也是下一个标准的一部分,但已经受到例如GCC和VC的最新版本的支持),您也可以使用其中一个:

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

答案 2 :(得分:0)

就像现在一样,setRxHandler原型获取一个指向函数的指针,该函数不返回任何内容并且需要int。正如您所注意到的,这不适用于成员函数,因为它们不能像普通函数一样被调用(您还必须处理this指针,这意味着要让该类的实例调用方法)。

要使它既可以使用成员函数又可以使用非特定的(泛型),您必须创建一个基类,并且要使用所有要使用的类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:

或使用模板:

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

使用模板选项,您实际上无法控制将使用setRxHandler(不包括RTTI)的类,这可能正是您想要的。

答案 3 :(得分:0)

您可以为Y创建基类并使用它(以避免“特定于类”),或使用模板:

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

但是这可能会引发如何使用成员函数的问题(如果有的话,请告诉我们)。

答案 4 :(得分:0)

正如其他人已经提到的,C ++不提供此功能。

您可以使用的另一个选项是libsigc++,它在gtkmm中广泛使用,请参阅教程中的this example,例如如何将指针传递给成员函数。您的示例可能类似于:

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