如何只调用名称的方法?

时间:2009-12-23 22:26:22

标签: c++ class methods

我正在尝试使用方法void run( string method )来运行该类中的方法。例如:

class Foo {
    public:
    void run( string method ) {
        // this method calls method *method* from this class
    }
    void bar() {
        printf( "Function bar\n" );
    }
    void foo2() {
        printf( "Function foo2\n" );
    }
}

Foo foo;

int main( void ) {
    foo.run( "bar" );
    foo.run( "foo2" );
}

这会打印出来:

Function bar
Function foo2

谢谢! :)

9 个答案:

答案 0 :(得分:15)

您可以创建一个std::map,它将字符串映射到成员函数指针,只要您要调用的所有函数都具有相同的签名。

地图将被声明为:

 std::map<std::string, void(Foo::*)()> function_map;

答案 1 :(得分:9)

正如其他人所指出的那样,C ++并没有开箱即用这种反思(并且可能不是你想做的事情。)

但是我会提到确实存在一些预处理器,它们为类类型和方法的子集实现了这个功能。 Qt的moc就是一个例子,它是信号/插槽机制的一部分。请注意QMetaObject ...

上的method()methodCount()

Qt执行此操作的方法是在构建过程中注入一个工具,该工具生成表并使用其余代码编译它们。这是你手工编写的所有内容 - 而不是语言功能。

答案 2 :(得分:6)

已经提到的地图解决方案适用于固定的函数列表,但我不认为在C ++中有一种方法可以像这样反省。也就是说,你不能有一个函数void perform( string methodName )说“我有一个名为methodName的方法吗?如果是,请调用它。”

答案 3 :(得分:3)

虽然之前的答案仅适用于您的解决方案,但您的解决方案看起来并不适合您的问题。

我有两个建议:1)构建一个更好的抽象基类或2)为函子(函数对象)使用基类。让我们更详细地看一下......

给定一个模拟处理器指令集的项目,我们可以用以下方式模拟执行:

struct Instruction_Interface
{
  virtual void execute(void) = 0;
};

typedef std::vector<Instruction_Interface *> Instruction_Container;

//...
Instruction_Container::iterator iter;
Instruction_Container program_instructions;
//...
for (iter =  program_instructions.begin();
     iter != program_instructions.end();
     ++iter)
{
  (*iter)->execute(); // Execute the instruction;
}

这允许调用每个指令的execute方法,无论指令类型如何。可以在界面中添加更多方法;在这个例子中,可以添加“toString”,它将指令转换为文本。

Idea 2:  Functors 

为要使用的函数建立基类或接口。将它们放入容器中并迭代容器。迭代也可以是有条件的:

struct Functor_Interface
{
   virtual std::string  get_name(void) const = 0;
   virtual void         execute(void) = 0;
   virtual void         execute_if_name(const std::string& name)
   { if (name == get_name())
     {
        execute();
     }
   }
};

typedef std::vector<Functor_Interface *> Functor_Container;
//...
Functor_Container the_functors;
//...
Functor_Container::iterator iter;
for (iter =  the_functors.begin();
     iter != the_functors.end();
     ++iter)
{
   (*iter)->execute_if_name("loader"); // Execute the functor if it is a *loader*.
   (*iter)->execute_if_name("math");
}

总之,考虑一下你的设计,看看是否有一个更好的过程不需要函数名,而是让函数决定执行或一般执行盲方法。

答案 4 :(得分:2)

您可以创建成员函数指针的映射,映射的键是函数的名称。但是指向成员函数的指针有点难以使用。

http://www.parashift.com/c++-faq-lite/pointers-to-members.html

更简单的方法是在run函数中执行一堆if-then-else块来调用相应的函数。

答案 5 :(得分:1)

正如其他海报所说,你需要在C ++中手工完成,因为该语言没有内置Reflection

C#和Java等语言都内置了这一点,因此根据您的需要,可能需要重新考虑您选择的语言。

答案 6 :(得分:1)

对于直接的C ++,上面的答案是好的。但是,一些工具包(例如,Qt)可以为C ++添加内省。这可能是一个更重的变化,而不是你想要的现有项目,但如果你正在启动一个可能需要内省的项目,那么值得搜索添加它的工具包/包装器。

答案 7 :(得分:0)

提到存在一些反映库,如CAMP:http://dev.tegesoft.com/projects/camp/apidoc/index.html

答案 8 :(得分:-3)

如果没有RTTI或某种地图,你就无法做到。或者像这样的解决方案:

class Foo {
    public:
    void run( string method ) {
        bar(method);
        foo2(method);
     // ... more methods here
    }
    void bar(string method) {
        if (method != "bar") return;
        printf( "Function bar\n" );
    }
    void foo2(string method) {
        if (method != "foo2") return;
        printf( "Function foo2\n" );
    }
}

Foo foo;

int main( void ) {
    foo.run( 'bar' );
    foo.run( 'foo2' );
}

这将为您提供您想要的相同结果