C++中能否实现通用函数数组?本人已掌握typedef用法
把不同签名的函数存入通用数组并调用的解决方案
嘿,这需求挺实际的——你想把不同参数类型/数量的函数塞进同一个数组里,还能正确调用它们,对吧?咱们先聊聊你原代码里的问题,再给你两种靠谱的实现方式。
首先得明确:C++的数组要求所有元素的类型完全一致,你原代码里的foo()(无参)和foo2(int)(带int参数)是不同的函数类型,直接丢进同一个数组会触发编译错误——编译器根本不知道这个数组的元素类型该设成啥。
那怎么解决?下面两种方法是日常开发里最常用的:
方法1:C++17+ 用 std::variant + std::function (推荐)
这种方式是现代C++里最简洁安全的方案,利用std::variant存储不同类型的可调用对象,再用std::visit来匹配调用。
先看完整示例代码:
#include <iostream> #include <functional> #include <variant> #include <array> void foo() { std::cout << "hello world" << std::endl; } void foo2(int a) { std::cout << "hello friend number " << a << std::endl; } // 定义能存两种函数类型的variant using FuncVariant = std::variant<std::function<void()>, std::function<void(int)>>; int main() { // 创建存储不同函数的数组 std::array<FuncVariant, 2> function_holder = {foo, foo2}; // 调用第一个无参函数 std::visit([](auto&& func) { // 编译期判断:这个函数能不能无参调用 if constexpr (std::is_invocable_v<decltype(func)>) { func(); } }, function_holder[0]); // 调用第二个带int参数的函数 std::visit([](auto&& func) { // 编译期判断:这个函数能不能接受int参数调用 if constexpr (std::is_invocable_v<decltype(func), int>) { func(1); } }, function_holder[1]); return 0; }
为啥推荐这个?
- 不需要手动管理内存(不像下面的多态方法要new/delete)
constexpr判断保证了编译期安全,不会出现运行时类型错误- 扩展性强:如果要加其他签名的函数,只需要给
FuncVariant加对应的std::function类型就行
方法2:C++11/14 用多态基类(兼容旧标准)
如果你的项目还在用C++17之前的标准,那可以用抽象基类+派生类包装的方式,利用多态来存储不同函数。
示例代码:
#include <iostream> #include <vector> // 抽象基类:所有函数包装类的父类 class BaseFunction { public: virtual ~BaseFunction() = default; // 必须定义虚析构,避免内存泄漏 }; // 包装无参函数的派生类 class NoArgFunction : public BaseFunction { public: using FuncType = void(*)(); NoArgFunction(FuncType func) : m_func(func) {} void call() { m_func(); } private: FuncType m_func; }; // 包装带int参数的派生类 class IntArgFunction : public BaseFunction { public: using FuncType = void(*)(int); IntArgFunction(FuncType func) : m_func(func) {} void call(int arg) { m_func(arg); } private: FuncType m_func; }; int main() { void foo() { std::cout << "hello world" << std::endl; } void foo2(int a) { std::cout << "hello friend number " << a << std::endl; } // 用vector存基类指针(数组也可以,vector更灵活) std::vector<BaseFunction*> function_holder; function_holder.push_back(new NoArgFunction(foo)); function_holder.push_back(new IntArgFunction(foo2)); // 调用时需要向下转型到对应的派生类 dynamic_cast<NoArgFunction*>(function_holder[0])->call(); dynamic_cast<IntArgFunction*>(function_holder[1])->call(1); // 记得手动释放内存! for (auto func_ptr : function_holder) { delete func_ptr; } return 0; }
注意点:
- 必须给基类加虚析构,否则派生类的析构函数不会被调用,会内存泄漏
- 调用时需要明确知道每个元素对应的派生类类型,用
dynamic_cast转型(转型失败会返回nullptr,记得做检查哦) - 如果要加更多签名的函数,就得新增对应的派生类,相对繁琐一点
内容的提问来源于stack exchange,提问作者Red_Shield
相关产品推荐
相关产品推荐

