You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:07:42