在类A
中,我有一个成员函数,它应该接收一个指向其他类函数的指针。所有这些函数都具有相同的签名(接收类型和返回类型)。
这样的事情:
class A{
private:
void (*onConfirmCallback) (); //pointer to function
public:
void setOnConfirmListener(void (*callback) ()); //member function that receives another member function from another class, and uses the pointer above to point to it
}
定义:
void A::setOnConfirmListener(void (*callback)())
{
onConfirmCallback = callback;
}
并且在课程A
中的某个时刻我调用了回调:
onConfirmCallback();
在课程B
中,我设置了回调:
class B{
private:
A a;
public:
B();
foo();
}
和定义:
B::B(){
a.setOnConfirmListener(foo);
}
B::foo(){
cout << "foo called" << endl;
}
我还有另一个类C
,它也有一个A
的实例,并且还设置了一个回调:
class C{
private:
A a;
public:
C();
foo2();
}
和定义:
C::C(){
a.setOnConfirmListener(foo2);
}
C::foo2(){
cout << "foo2 called" << endl;
}
我尝试了不同的声明变体,上面的代码会生成此错误:
没有用于调用'A :: setOnConfirmListener()'
的匹配函数
我理解“指向函数的指针”与“指向成员函数的指针”不同。所以我也尝试将void (*onConfirmCallback) ()
更改为void (B::*onConfirmCallback) ()
,但我不认为这很好,因为这个指针应该对不同的类(不是从相同的基类派生)进行回调,而不仅仅是{ {1}}。
有没有办法实现这个?
基本上我正在尝试做一些像Java的界面......
答案 0 :(得分:4)
使用std::function
而不是函数指针。
class A {
private:
std::function <void()> onConfirmCallback; //pointer to function
public:
void setOnConfirmListener(std::function <void()>);
};
您可以将非会员功能直接传递给setOnConfirmListener
。当涉及到成员函数时,您需要一个对象来调用它们:
class B {
private:
A a;
public:
B();
void foo();
};
B::foo(); // invalid and makes no sense
B* b = new B; b->foo(); // OK
所以下面的行也不会起作用:
a.setOnConfirmListener(&B::foo); // invalid and makes no sense
您可以使用std::bind
:
a.setOnConfirmListener(std::bind(&B::foo, b)); // OK
b
可以是B&
,B*
或std::shared_ptr<B>
。
使用this
(或*this
)作为bind
的第二个参数可能有点危险,因为您现在负责监视对象何时不存在并取消注册所有对象其相关的听众。一种方法是从enable_shared_from_this
派生您的对象,并使用std::shared_ptr
而不是原始this
指针。这意味着您的对象在至少一次回调中被注册为侦听器之前不会被销毁。
另一种方法是从同一个抽象基类派生所有侦听器,比如Listener,并使用指向Listener的指针而不是函数指针。
class Listener
{
public:
virtual void callback() = 0;
};
class A {
private:
std::shared_ptr<Listener> listener; // or another smart pointer
public:
void setOnConfirmListener(std::shared_ptr<Listener> listener);
};
class B : public Listener {
private:
A a;
public:
B();
void foo();
void callback() { foo(); }
};
缺点是必须从同一个基类派生所有侦听器。此外,如果同一个类需要有多个侦听器回调,那么你必须跳过一些箍。