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

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

本文关键字:对象 函数 指针 实例化 不能 引用 为什么      更新时间:2023-10-16

EDITstd::function+ lambda 来救援。请参阅检查答案。

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

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

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

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

我发现解决方法是使函数static(和成员数据(,但我只是在黑客攻击,直到编译器关闭并且代码正常工作,而不是我最喜欢的编程模式。

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

#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
}

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

这是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,请看一下这里。

你的代码有几个问题。

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

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

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

classA.set_callback(&B::print); 

最后但并非最不重要的一点是,您需要有一个类的实例来调用其成员函数。因此在这里,

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

仅调用成员函数指针是行不通的。您应该有一个B类的实例来调用其成员。你需要,像

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