指向不同类的成员函数的指针

Posted

技术标签:

【中文标题】指向不同类的成员函数的指针【英文标题】:Pointer to member functions of different classes 【发布时间】:2015-12-16 08:23:32 【问题描述】:

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) () ,但我不认为这很好,因为这个指针应该保存对不同类(不是从同一个基类派生)的回调,而不仅仅是 B

有没有办法实现这个?

基本上我正在尝试做一些类似 Java 的界面的事情......

【问题讨论】:

C++ Horatio 中的东西比你的哲学梦想中的要多:例如C++确实有接口!构建一个只有纯虚方法的基类。 如果问题是如何在 C++ 中创建接口,@PaoloM 的答案正是您要寻找的。如果这不是问题,那应该是:) 嗯,好的。马上尝试 这里的根本问题是B::foo 不是一个不带参数并返回void 的函数。这是一个成员函数,它们是一种完全不同的动物。 (非静态)成员函数只能在对象上调用,因此它实际上有一个隐藏的第一个参数,它是指向它所应用的对象的指针。而且,不,你不能把它当作是这样写的。 【参考方案1】:

使用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&amp;B*std::shared_ptr&lt;B&gt;

使用this(或*this)作为bind 的第二个参数可能有点危险,因为您现在负责监控您的对象何时不再存在并注销其所有关联的侦听器。解决此问题的一种方法是从enable_shared_from_this 派生您的对象并使用std::shared_ptr 而不是原始的this 指针。这意味着您的对象在至少一个回调中注册为侦听器之前不会被销毁。

另一种方法是从同一个抽象基类(例如 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(); 
;

缺点是必须从同一个基类派生所有侦听器。另外,如果同一个类需要有多个监听器回调,你必须跳过一些环节。

【讨论】:

第二种选择不适合我。但是,在第一个替代方案中,您实际上在 B 本身中创建了一个 B 实例,将其与函数 foo “绑定”,然后将其发送到 a.setOnConfirmListener() 您可以将引用或指针绑定到对象(例如*thisthis)。创建另一个实例通常没有意义。 我明白了。伟大的!这适用于“B”类。也尝试发送C 的回调... 无论如何我认为你的意思是B* b = new B()而不是B* b = new b

以上是关于指向不同类的成员函数的指针的主要内容,如果未能解决你的问题,请参考以下文章

C++ 指向具有匹配函数签名的任何类的成员函数的指针

不同类的成员函数指针的C++映射

什么类型可以保存 C++ 中不同类的成员函数指针?

为啥指向成员函数的指针不像数据指针那样只是内存地址

指向不完整类型成员函数的指针

C++ 指向成员函数指针问题