【问题标题】:C++ pointer to class method指向类方法的 C++ 指针
【发布时间】:2014-10-10 18:42:31
【问题描述】:

我想做这样的事情:

struct CLI_Command{
    CLI_Command(char* s, void (*h)(void)){
        command_string = s;
        handler = h;
    }

    char* command_string;
    void (*handler)(void);
};

class CLI  {
    public:
        CLI();

    private:
        CLI_Command cli_table[NO_CLI_COMMANDS] = {
                CLI_Command("Command1",   handler1),
                CLI_Command("Command2",   handler2)
        };

        void handler1(){};
        void handler2(){};
};

我知道我需要类似于 CLI::*handler 的东西,但我无法正确使用语法。我一直遇到这样的错误:

"error: no matching function for call to 'CLI_Command::CLI_Command(const char [4], <unresolved overloaded function type>)"

【问题讨论】:

  • 问题是你试图获取一个非静态成员函数的地址,这是不允许的。我最近有answered 一个类似的问题。也许它会帮助你。请注意,现代 C++ 提供了强大的工具,让您的程序更简洁、更安全。
  • @5gon12eder:获取非静态成员函数的地址是完全合法的,但结果是指向成员的指针,而不是函数指针。
  • @5gon12eder 好的,你能详细说明一下这些工具吗?或者指点我一个方向? :) 。我正在通过嵌入式设备上的 UART 创建命令行界面。
  • @BenVoigt 是的,这当然是正确的。所以不允许的事情是“将非静态成员函数的地址用作函数指针”。
  • @Jolle 例如,您可以将表设置为std::map&lt;std::string, Command&gt;,其中Command 可能是适当的typedef,或者 – 如果您想要更多的 OO 并且可以承受开销,请创建一个 @ 987654327@ 并将多态命令对象放入您调用虚函数的映射中。

标签: c++ class methods function-pointers


【解决方案1】:

这说明了正确的语法:

class CLI;

struct CLI_Command
{
    CLI_Command(char* s, void (CLI::*h)(void))
    {
        command_string = s;
        handler = h;
    }

    char* command_string;
    void (CLI::*handler)(void);

    void raise( CLI* the_cli ) { return (the_cli->*handler)(); }
};

class CLI
{
    public:
        CLI();

    private:
        static CLI_Command cli_table[NO_CLI_COMMANDS];

        void handler1(){};
        void handler2(){};
};

CLI::CLI_Command cli_table[NO_CLI_COMMANDS] = {
  { "Command1",   &CLI::handler1 },
  { "Command2",   &CLI::handler2 }
};

成员函数的名称不会衰减为指向成员的指针。在创建指向成员的指针时,您必须明确使用 &amp; 和限定名称。

【讨论】:

    【解决方案2】:

    除了其他答案,另一种选择是将std::functionstd::bind()一起使用:

    struct CLI_Command{
        ...
        std::function<void> handler;
    };
    
    class CLI {
        ...
        CLI_Command cli_table[NO_CLI_COMMANDS] = {
          { "Command1",   std::bind(&CLI::handler1, this) },
          { "Command2",   std::bind(&CLI::handler2, this) }
        };
    
        void handler1(){};
        void handler2(){};
    };
    

    【讨论】:

    • 太酷了。你知道这会产生多少开销吗?我的目标是一个小型嵌入式设备,所以我负担不起太多开销:)。
    • @Jolle 没问题,这是为了完整性,所以这个问题可能对其他人有帮助。
    • 实际上这是一个问题,因为我不知道这是否会产生任何开销:)
    • Heh :) 实际上它可能会根据实现带来一些开销,但另一方面它带来了更多的灵活性。
    【解决方案3】:
    void handler1(){}
    void handler2(){}
    

    CLI 的成员函数。 “寻址”它们的正确方法是&amp;CLI::handler1 而不是handler1。但是,void (*h)(void) 不会接受它们,需要将其更改为 void (CLI::*h)(void)。但这可能不是你想要的。

    也许考虑阅读有关 std::function 的信息以进行类型擦除,或​​者将您的 handler1/handler2 设为静态。

    【讨论】:

      【解决方案4】:

      您应该使用指向类成员的指针的语法,而不是松散函数指针的语法。

      class CLI;
      
      struct CLI_Command{
          CLI_Command(char* s, void (CLI::*h)(void)){
              command_string = s;
              handler = h;
          }
      
          char* command_string;
          void (CLI::*handler)(void);
      };
      

      另外,一定要通过当前CLI类的指针调用函数;

      void CLI::process(char *cmd) {
          CLI_Command command* = /* lookup the command */
          this->(command->handle)();
      }
      

      【讨论】:

      • 在处理指向成员的指针时需要-&gt;*(或.*)。
      【解决方案5】:

      为了让它发挥作用,让你的方法static

      static void handler1(){};
      static void handler2(){};
      

      无论后果如何(请read here,以获取更多详细信息):-( .

      【讨论】:

        猜你喜欢
        • 2010-09-08
        • 1970-01-01
        • 1970-01-01
        • 2010-12-05
        • 1970-01-01
        • 2015-04-18
        • 2017-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多