为什么我不能引用指向实例化对象函数的指针?

Why can't I reference a pointer to a function of an instantiated object?

编辑std::function + lambda 来救援。查看已检查的答案。

编辑:我添加了更多细节,我想要一个通用的解决方案,而不是绑定到 Class B 的定义。

在下面的示例中,我尝试将一个 class 中的函数指针设置为另一个 class 实例中的函数(具有相同的函数指针类型),而 Microsoft C++ 是告诉我:

C++ a pointer to a bound function may only be used to call the function

是否因为包含回调的对象可能在第一个对象之前被破坏?我正在将一些 Python 翻译成 C++,这种模式在 Python 中似乎不是问题。

我发现解决方法是创建函数 static(和成员数据),但我只是在修改,直到编译器关闭并且代码正常工作,这不是我最喜欢的编程模式。

如果不允许这种模式,关于如何在没有静态的情况下动态执行此操作的任何建议objects/functions?

#include <iostream>
#include <string>

typedef void (*callback_function_a)(int);

struct A 
{
    A() {
        cbk = nullptr;
    };
    void print_int(void) 
    {
        if (cbk != nullptr) {
            cbk(10);
        }
    }
    void set_callback(callback_function_a _cbk)
    {
        cbk = _cbk;
    };
    callback_function_a cbk;
};

struct B 
{
    B(std::string _header) 
    {
        header = _header;
    }
    void print(int x) {
        std::cout << header << x << std::endl;
    }
    std::string header;
};

void print(int x)
{
    std::cout << "Non-member func: " << x << std::endl;
}

int main() 
{
    A classA;
    B classB(std::string("MessageFrom classB:"));
    /// How do I make both of these work? I want to be able to pass in any 
    /// function of type callback_function_a?
    classA.set_callback(print); // OK
    classA.set_callback(classB.print); // <--- error here
}

您的代码有几个问题。

首先成员函数指针和自由函数指针类型不同。对于成员函数指针,你应该有

typedef void (B::*callback_function_a)(int);
//            ^^^^
// or
// using callback_function_a = void (B::*)(int);

其次,传递成员函数应该有语法&ClassName::MemberFunction,也就是说,你必须

classA.set_callback(&B::print); 

最后但同样重要的是,您需要有一个 class 的实例来调用它的成员函数。所以在这里,

void print_int(void) {
   if (cbk != nullptr) {
      // cbk(10);  // will not work
   }
}

简单地调用成员函数指针是行不通的。您应该有一个 B class 的实例来调用它的成员。你需要,像

#include <functional>  // std::invoke (required C++17)

void print_int()
{
   if (cbk != nullptr)
   {
      (/*instance of B class*/.*cbk)(10);
      // or simply using `std::invoke`
      // std::invoke(cbk, /*instance of B*/, 10);
   }
}

除了 Jejo 的出色回答之外,还有一件事可以添加,那就是,您可以创建成员函数 static,然后将其作为参数直接传递 set_callback().

示例:

class B {
...
static void print(int x) {
    // can't use class members in static member functions
    std::cout << /* header << */ x << std::endl;
}
...
};

main()

classA.set_callback(&B::print); 

指向自由函数的函数指针和指向成员函数的函数指针是两个不同的东西。要解决这个问题,我们需要某种包装器。

这是 std::function 的良好用例之一。它是具有给定签名的类型擦除的可调用对象。

为了使其更通用,您应该制作 set_callback 模板,这样您就可以接受可分配给 std::function.

的任何类型的可调用对象
#include <iostream>
#include <string>
#include <functional>

struct A {
    A() {
        cbk = nullptr;
    };
    void print_int(void) {
        if (cbk != nullptr) {
            cbk(10);
        }
    }
    template <typename Func>
    void set_callback(Func _cbk) {
        cbk = _cbk;
    };
    std::function<void(int)> cbk;
};

struct B {
    B(std::string _header) {
        header = _header;
    }
    void print(int x) {
        std::cout << header << x << std::endl;
    }
    std::string header;
};

void print(int x) {
    std::cout << "Non-member func: " << x << std::endl;
}

int
main() {
    A classA;
    B classB(std::string("MessageFrom classB:"));
/// How do I make both of these work? I want to be able to pass in any 
/// function of type callback_function_a?
    classA.set_callback(print); // OK
    classA.set_callback([&](int i) { classB.print(i); }); // <--- now works as well
}

如果您不熟悉 [&](int i) { classB.print(i); } 等 lambda,请查看 here