如何在C++中用vector存储函数以实现菜单系统?
C++菜单系统:在vector中存储函数的正确实现
问题描述
我想知道是否可以在vector中存储函数?目前我正在尝试用C写一个菜单系统,但主菜单之后的实现遇到了困难。我希望创建多个Menu对象并传给showMenu()函数,让这个函数调用对应菜单项绑定的函数。我是不是应该在vector里存函数指针?我研究过C的std::function库,但实现有问题,以下是我的错误代码:
错误代码片段
struct Menu { vector<string> items; vector<function> functions; // 错误:std::function需要指定函数签名 };
Menu mainMenu = { { "Quit", "Income Menu", "Expenses Menu" }, { return, showMenu(incomeOptions), showMenu(expenseOptions) } // 错误:return不是函数,showMenu调用会立即执行 }; Menu incomeOptions = { {"Back" , "Add Income", "Edit Income"}, { return, addIncome(), editIncome()} // 错误:同上 }; Menu expenseOptions = { {"Back" , "Add Expense", "Edit Expense"}, { return, addExpense(), editExpense()} // 错误:同上 };
void showMenu(Menu menu, string title = "") { system("cls"); if (title != "") { cout << "================ [" << title << "] ================" << endl; cout << endl; } for (int i = 0; i < menu.items.size(); i++) { cout << " (" << i << ") " << menu.items[i] << endl; } int selection; cout << " > "; cin >> selection; if (selection >= 0 && selection < menu.items.size()) { // 错误:仅访问函数对象,未执行调用 menu.functions[selection]; } else { showMenu(menu, title); } }
int main() { showMenu(mainMenu, "Main Menu"); }
简洁解决方案
核心修正点
- 指定std::function的签名:所有菜单操作都是无参数无返回值的函数,因此使用
std::function<void()>作为vector的元素类型 - 使用lambda表达式延迟执行:避免直接调用函数(如
showMenu(incomeOptions)会立即执行),用lambda包装需要延迟触发的操作 - 函数对象的调用语法:存储的函数对象需要通过
()来执行 - 传引用优化:showMenu参数改用引用传递,避免不必要的对象拷贝
修正后的完整代码
#include <vector> #include <string> #include <functional> #include <iostream> #include <cstdlib> // 用于exit() using namespace std; struct Menu { vector<string> items; vector<function<void()>> functions; // 指定无参无返回值的函数签名 }; // 提前声明菜单对象,解决初始化依赖问题 Menu mainMenu; Menu incomeOptions; Menu expenseOptions; // 菜单操作函数示例(根据需求实现具体逻辑) void addIncome() { system("cls"); cout << "=== 添加收入 ===" << endl; // 这里写添加收入的逻辑 cout << "操作完成,按任意键返回..." << endl; system("pause"); showMenu(incomeOptions, "收入菜单"); } void editIncome() { system("cls"); cout << "=== 编辑收入 ===" << endl; // 这里写编辑收入的逻辑 cout << "操作完成,按任意键返回..." << endl; system("pause"); showMenu(incomeOptions, "收入菜单"); } void addExpense() { system("cls"); cout << "=== 添加支出 ===" << endl; // 这里写添加支出的逻辑 cout << "操作完成,按任意键返回..." << endl; system("pause"); showMenu(expenseOptions, "支出菜单"); } void editExpense() { system("cls"); cout << "=== 编辑支出 ===" << endl; // 这里写编辑支出的逻辑 cout << "操作完成,按任意键返回..." << endl; system("pause"); showMenu(expenseOptions, "支出菜单"); } // 初始化所有菜单 void initMenus() { mainMenu = { {"退出", "收入菜单", "支出菜单"}, { [](){ exit(0); }, // 退出程序 [](){ showMenu(incomeOptions, "收入菜单"); }, // 打开收入菜单 [](){ showMenu(expenseOptions, "支出菜单"); } // 打开支出菜单 } }; incomeOptions = { {"返回主菜单", "添加收入", "编辑收入"}, { [](){ showMenu(mainMenu, "主菜单"); }, // 返回主菜单 addIncome, // 直接传递函数名(匹配签名即可) editIncome } }; expenseOptions = { {"返回主菜单", "添加支出", "编辑支出"}, { [](){ showMenu(mainMenu, "主菜单"); }, addExpense, editExpense } }; } void showMenu(Menu& menu, const string& title = "") { // 传引用避免拷贝 system("cls"); if (!title.empty()) { cout << "================ [" << title << "] ================" << endl; cout << endl; } for (size_t i = 0; i < menu.items.size(); i++) { // 使用size_t适配容器大小类型 cout << " (" << i << ") " << menu.items[i] << endl; } int selection; cout << " > "; cin >> selection; if (selection >= 0 && static_cast<size_t>(selection) < menu.items.size()) { menu.functions[selection](); // 调用存储的函数对象 } else { cout << "无效选择,请重新输入!" << endl; system("pause"); showMenu(menu, title); } } int main() { initMenus(); // 先初始化所有菜单 showMenu(mainMenu, "主菜单"); return 0; }
关键说明
- lambda表达式:用于实现返回主菜单、打开子菜单这类需要动态触发的操作,它会创建一个可调用的函数对象,只有在调用时才会执行内部逻辑
- std::function的灵活性:不仅可以存储普通函数指针,还能存储lambda、绑定了参数的函数对象等,适配多种可调用类型
- 初始化顺序:提前声明所有Menu对象,再通过initMenus函数统一初始化,解决了菜单之间的依赖问题
内容的提问来源于stack exchange,提问作者Cason
相关产品推荐
相关产品推荐

