class 的成员函数上的函数指针

Function pointers on a class's member function

void Parser::add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand)
{
    command_no_arg.push_back(comand);
    func_no_arg.push_back(f);
}

void Parser::prepare()
{
    //add_func_no_arg(Virtual_Machine::dump,"dump"); it work when i put it in static but i cant do that
    add_func_no_arg(vm.clear,"clear"); // ERROR HERE the vm.clear does not fit
}

我有这两个函数可以帮助我创建一个指针数组func_no_arg; 我无法将虚拟机的功能置于静态状态; 当一个函数在一个对象中被“陷阱”时,为什么我不能在函数上有一个指针?也许类型有误,这里是一些 .hpp :

class Parser {
    public:
       /***/
        void prepare();
        void add_func_no_arg(void (Virtual_Machine::*f)(), std::string comand);

    private:
        Virtual_Machine vm;
        std::vector<std::string> command_no_arg;
        std::vector<void (Virtual_Machine::*)()> func_no_arg;
        /***/

};


class Virtual_Machine {
    public:
      /***/
        void clear();
      /***/
}

编译器是这样说的:

Parser.cpp: In member function ‘void Parser::prepare()’:
Parser.cpp:65:36: error: invalid use of non-static member function ‘void Virtual_Machine::clear()’
     add_func_no_arg(vm.clear,"dump");
                                    ^
In file included from ../include/Parser.hpp:13,
                 from Parser.cpp:8:
../include/VM.hpp:23:14: note: declared here
         void clear();

获取指向成员的指针的语法是&Virtual_Machine::clear(不是vm.clear),并且可以在[=的实例上调用这种类型的变量f 13=] 与 .* 运算符(例如 vm.*f())。

或者您可以写 &decltype(vm)::clear,这不取决于 class 名称。

正如 IlCapitano 所写,您必须使用特定的语法来处理指向成员的指针。这是一个示例(使用 g++ tmp.cpp -o tmp 编译):

#include <iostream>
#include <string>
#include <vector>

class Virtual_Machine
{
    private:
        std::string name;

    public:
        Virtual_Machine(std::string n) : name(n) {}
        void clear() { std::cout << "Clear " << name << std::endl; }
};

class Parser
{
    private:
        Virtual_Machine vm;
        std::vector<std::string> command_no_arg;
        std::vector<void (Virtual_Machine::*)()> func_no_arg;

    public:
        Parser(std::string vm_name) : vm(vm_name) {}
        void add_func_no_arg(void (Virtual_Machine::* f)(), std::string command)
        {
            command_no_arg.push_back(command);
            func_no_arg.push_back(f);
        }
        void prepare()
        {
            add_func_no_arg(&Virtual_Machine::clear, "clear");
        }
        void test()
        {
            (vm.*(func_no_arg[0]))();
        }
};

int main()
{
    Parser a("vm_a"), b("vm_b");

    a.prepare();
    b.prepare();

    a.test();
    b.test();

    return 0;
}

程序的输出是:

Clear vm_a
Clear vm_b

指向 class Virtual_Machine 实例的成员函数 clear 的指针是用 &Virtual_Machine::clear 创建的。要稍后调用此函数,您必须使用运算符 .*->* 以及运算符左侧的 class 实例和右侧函数的指针,喜欢 (vm.*(func_no_arg[0]))()。如果函数有参数,您可以将它们放在最右边的一对括号中。

如上所述,获取成员函数指针的正确语法是&Class::member。这背后的一般思想是,当您声明一个 class 时,该 class 中的每个函数和类型都属于以您的 class 命名的命名空间。因此,获取指向成员函数的指针的语法实际上等同于指向命名空间内函数的任何指针。请记住,在 class.

中尝试检索指向函数的指针时,访问说明符仍然适用

然而,有一个很大的区别,当你声明一个成员函数时,添加了一个隐式参数(c++中的this),你实际上已经注意到了,这就是为什么类型是return_type (Class::*) (parameters)

这件事有两种处理方式。第一个,正如其他人在这里指出的那样,是在需要调用函数时使用实例,方法是使用 .* or ->* 语法(点或箭头用于访问实例“内部”,星号用于取消引用函数指针)。 另一种方法(主要是如果您不关心该对象,或者在调用它时无法访问它)是通过“绑定”隐式 [=11] 将您的函数包装在 std::function 中=],以及您需要的任何参数,使用 std::bind。 通过一起使用 std::functionstd::bind,您将能够使用您习惯的 c 风格语法。

cppreference 上 std::function and std::bind 的示例部分展示了如何实现这一点