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

问题描述 投票:1回答:3

编辑: std::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
}
c++ class c++11 function-pointers member-function-pointers
3个回答
2
投票

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

这是对 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
}

如果你对lambdas不熟悉,如 [&](int i) { classB.print(i); } 看一看 此处.


3
投票

你的代码有几个问题。

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

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

1
投票

除了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); 
© www.soinside.com 2019 - 2024. All rights reserved.