如何创建一个存储指向成员函数的指针的类 (C++)

Posted

技术标签:

【中文标题】如何创建一个存储指向成员函数的指针的类 (C++)【英文标题】:How to create a class that stores pointers to member functions (C++) 【发布时间】:2020-06-25 21:59:57 【问题描述】:

我正在尝试创建一个类,该类存储指向其他类的成员函数的指针,并且可以从文本命令(如游戏控制台)执行。

根据此处找到的示例,我做了一些功能性的事情,它存储具有类似字符串的输入的成员。下面是我的实现。

文件: Command.hpp

#include <string>
#include <functional>
#include <unordered_map>
#include <string>
#include <iostream>
    
using namespace std;

class Command

    public:
        Command();
        virtual ~Command();
        void RegisterCommand(string command, function<void(const string&)> fun);
        void Run(const string& command, const string& arg);

    private:
        unordered_map<string, function<void(const string&)>> functions;
;

文件: Command.cpp

Command::Command()



Command::~Command()



void Command::RegisterCommand(string command, function<void(const string&)> fun)

    functions[command] = fun;


void Command::Run(const string& command, const string& arg)

    functions[command](arg);

文件: main.cpp

#include "Command.hpp"

// function to register
void xyz_fun(const string& commandLine)

    cout << "console output: " << commandLine << endl;


int main(int argc, char* argv[])

    Command m_Cmd;

    // Register function
    m_Cmd.RegisterCommand("xyz_fun", xyz_fun);
    
    // Run registered function
    m_Cmd.Run("xyz_fun", "hello world.");

    return EXIT_SUCCESS;

我的问题是如何实现一个通用类来存储具有未知输入参数(布尔值、整数、双精度值、字符串等)的成员。

例如,我可以这样做:

m_Cmd.RegisterCommand("xyz_fun2", xyz_function2);

然后打电话

m_Cmd.Run("xyz_fun2", false)

它有一个布尔参数而不是一个字符串。

提前感谢您的关注,欢迎提供任何帮助。

【问题讨论】:

如果 Run 被错误的参数调用,你想发生什么? “存储指向成员函数的指针的类” -- 这与您的代码不匹配。您的代码使用函数对象,而不是函数指针。 (我建议保留代码并更改问题的文本和标题。函数对象看起来更适合您的目标。) 你如何决定传递哪个参数值?例如,为什么m_Cmd.Run("xyz_fun2", false) 而不是m_Cmd.Run("xyz_fun2", true) 你好,JaMiT。非常感谢您的 cmets。也许我表达得不好。我的目标是实现一个类来处理用户传递的命令。它们是简单的命令,其中大多数的唯一目的是更改一些现有的标志。例如:随着程序的运行,用户可以输入命令来改变窗口大小。或者通过文本文件以自动方式执行此操作(类似于脚本)。 抱歉我的困惑问题。我是 C++ 的新手。 【参考方案1】:

代替

        unordered_map<string, function<void(const string&)>> functions;

你可以的

        union acceptable_types  int i; char c; bool b; std::string* s; ... ;
        unordered_map<string, function<void(acceptable_types)>> functions;

然后在调用函数时,只需将函数想要的值放入acceptable_types类型的变量中即可。 如果一个函数想要使用一个特定的值,它应该只使用acceptable_types union 的一个特定成员。 这是一个例子:

#include "Command.hpp"

void
my_bool_func (acceptable_types union_param)

        bool bool_var = union_param.b;
//      ...
//      Use bool_var
//      ...


void
my_string_func (acceptable_types union_param)

        std::string string_var = *(union_param.s);
//      ...
//      Use string_var
//      ...


int
main(int argc, char* argv[])

        Command my_command;
        acceptable_types union_var;

        my_command.RegisterCommand("my_bool_func", my_bool_func);
        my_command.RegisterCommand("my_string_func", my_string_func);

        union_var.b = true;
        my_command.Run("my_bool_func", union_var);

        *(union_var.s) = "hello world.";
        my_command.Run("my_string_func", union_var);

        return 0;

【讨论】:

union 和指向 std::string 的原始指针都不是一个好主意。 union 特别不安全,尤其是在没有像这里那样进行类型跟踪/检查的情况下。在这种情况下,您应该推荐 std::variant,因为它具有类型检查和值语义。 事实证明:您已经编写/推荐了未定义的行为。在这里执行*(union_var.s) = "hello world."; 是荒谬的,因为您从未在该地址分配任何std::string,因此您无法取消引用它。你正在使用一个无效的、未初始化的指针,破坏了不属于你的内存。即使你确实分配了它,你也会建议新手用 C++ 编写 newdelete,这可能是 99% 以上的 C++ 编码人员永远不需要的东西。

以上是关于如何创建一个存储指向成员函数的指针的类 (C++)的主要内容,如果未能解决你的问题,请参考以下文章

C ++创建指向标头内所有公共静态成员函数的指针数组,然后使用它

C++,成员函数返回对包含指向 const 对象的指针的向量的 const 引用

C++ Visual Studio 非标准语法使用 '&' 创建指向成员的指针

指向具有私有构造函数的类的类成员的指针

C++|详解类成员指针:数据成员指针和成员函数指针及应用场合

C++成员函数指针指向全局函数指针