【问题标题】:Calling a function depending on a variable?根据变量调用函数?
【发布时间】:2017-01-19 00:44:01
【问题描述】:

你能根据整数是多少来调用函数吗?

这就是我的意思:

#include <iostream>

using namespace std;

int whichFunction;

int main()
{
    cout << "Which function do you want to call?";
    cin >> whichFunction;

    function[whichFunction](); 
    //If you entered 1, it would call function1 - same with 2, 3
    //or Hihihi (of course only when whichFunction would be a string)
}


void function1()
{
    cout << "Function No. 1 was called!";
}

void function2()
{
    cout << "Function No. 2 was called!";
}

void functionHihihi()
{
    cout << "Function Hihihi was called!";
}

我知道这行不通,但我希望你能明白。

那么有没有办法做这样的事情?

【问题讨论】:

  • 是的。 Function pointer.
  • 如果函数编号在编译时已知,则可以特化函数模板。

标签: c++


【解决方案1】:

是的,有办法做到这一点。

//Array for the functions
std::array<std::function<void()>, 3> functions = { &function1, &function2, &function3 };

//You could also just set them manually
functions[0] = &function1;
functions[1] = &function2;
functions[2] = &function3;

那么你就可以把它当成一个普通的数组来使用了:

functions[whichFunction](); //Calls function number 'whichFunction'

请注意,所有函数都必须具有相同的签名。


如果由于某种原因不想使用std::function,可以使用function pointers

【讨论】:

  • 因为这包括用户输入,所以边界检查是合适的。
  • @adnan_e 嗯,是的。但我认为这是隐含的。
  • @Raindrop7: 你把它们做成模板并写一个漂亮的 TMP 循环 :)
  • @cat 我其实不知道 :) 好吧,我想我可以...谢谢
  • @Raindrop7 如果你有 1000 个函数,你必须一个一个地编写、记录和测试它们。然后为每个数组添加一个元素相比之下就有点负担了
【解决方案2】:

您可以使用多态性概念(通过虚函数和继承)。

这是一个非常基本的方案:

#include <iostream>
#include <vector>

using namespace std;

class Obj
{
public:
    virtual void function() = 0;
};

class Obj1 : public Obj
{
public:
    virtual void function() {cout << "Function No. 1 was called!";}
};

class Obj2 : public Obj
{
public:
    virtual void function() {cout << "Function No. 2 was called!";}
};

class Obj3 : public Obj
{
public:
    virtual void function() {cout << "Function No. 3 was called!";}
};

int main()
{
    vector<Obj*> objects;
    objects.push_back(new Obj1);
    objects.push_back(new Obj2);
    objects.push_back(new Obj3);

    cout << "Which function do you want to call?";
    int whichFunction;
    cin >> whichFunction;
    if (1 <= whichFunction && whichFunction <= objects.size())
        objects[whichFunction-1]->function();

    for (auto object : objects)
        delete object;

    return 0;
}

【讨论】:

  • 哇,对于如此简单的任务,这是一种可怕的方法。此外,删除没有虚拟析构函数的抽象类类型的对象会导致 U.B.
  • @adnan_e:这么简单的任务根本不需要函数指针。我假设 OP 要求这样做是为了对更复杂的事情有一个大致的了解。
  • 是的,您正在通过使用虚拟调用和为每个需要的值创建一个新类来发明一个简单的函数指针。使用 types 并知道在编译时使用哪种类型是有好处的,但模板会更好。
  • @JDługosz:抛开评论中表达的粗鲁不谈,虚函数本质上是一个函数指针(仅在运行时解析,而不是在编译期间解析的非虚函数)。
【解决方案3】:

支持字符串输入:

std::map<std::string, std::function<void()>> le_mapo;
le_mapo["1"] = &function1;
le_mapo["2"] = &function2;
le_mapo["3"] = &function3;
le_mapo["Hihihi"] = &functionHihihi;

std::string input;
std::cin >> input;

auto check = le_mapo.find(input);

if (check != le_mapo.end()) 
{
    le_mapo[input](); //call function
}
else
{
    //not found
}

写得太长?为风暴做准备!

#define BE_EVIL(map, function, x) map[ #x ] = & function ## x
//custom macro with predefined function name (here: just function)
#define BE_EVIL_FUN(map, x) BE_EVIL(map, function, x)
//same, with predefined map name
#define BE_EVIL_JUST_X(x) BE_EVIL_FUN(le_mapo, x)

并使用:

//"connect" string to function
BE_EVIL(le_mapo, function, 1); //le_mapo[ "1" ] = & function1;

【讨论】:

  • 您可以使用初始化列表而不是分配给每个项目。不需要邪恶,甚至更短!
【解决方案4】:

使用函数指针是件好事:

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


void foo1(){cout << "Foo1 says hello!" << endl;}
void foo2(){cout << "Foo2 says hello!" << endl;}
void foo3(){cout << "Foo3 says hello!" << endl;}
void foo4(){cout << "Foo4 says hello!" << endl;}


int main()
{

    system("color 1f");

    int input;
    cout << "Which function you wanna call: ";
    cin >> input;
    cout << endl;


    void (*pFunc)() = NULL;

    switch(input)
    {
        case 1:
            pFunc = foo1;
        break;
        case 2:
            pFunc = foo2;
        break;
        case 3:
            pFunc = foo3;
        break;
        default:
            cout << "No function available!" << endl;
    }

    if(NULL != pFunc) //avoiding usage of a NULL ptr
        (*pFunc)();

    cout << endl << endl << endl;
    return 0;
}

【讨论】:

  • 这与if 级联基本相同,OP 表示他希望避免这种情况。
  • @adnan_e:如果你只使用 if 并且想要调用该函数,那么它就可以了。但是,如果您想根据 Precedent 输入稍后调用该函数 x 次怎么办?所以你需要一次又一次地切换!这很烦人。所以改为将函数地址存储在一个指向函数的指针中,每次你想根据最后一个输入调用它时切换一次,可以使用指针
  • 我没有说你是对是错,我说OP说他在寻找一种不同的方式。
【解决方案5】:
switch(whichFunction) {
    case 1: function1(); break;
    case 2: function2(); break;
    case 3: function3(); break;
}

【讨论】:

  • 这比所有函数指针(或更差)的解决方案都好很多
  • @M.M:嗯,这是你的意见。现在,如果用户想根据rand() % 2 将代码中间的“数组”中的function2() 替换为function2a() 怎么办?
  • @lorro case 2: if ( rand() % 2 ) function2a(); else function2(); break;
  • @M.M:我想说的是,我希望它成为一种状态,我会选择function2() 还是function2a()。通过在此处放置switch,您正在重复您在其他地方(可能在课堂上)的状态。
  • @lorro 不知道你在说什么,没必要在别处重复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 2021-01-19
  • 2011-09-08
  • 2021-11-27
  • 2018-07-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多