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

新手技术问询:如何用带不同方法签名的std::function理解多态类

用std::function实现多态运算示例(理解类型擦除)

嘿,这个思路太棒了!用std::function来封装不同数学运算,刚好能直观展示类型擦除和运行时多态的核心逻辑,非常适合新手入门。我来帮你把这个示例补全并拆解清楚:

第一步:定义基础运算函数

先把你提到的(以及补充的)运算函数写完整:

#include <iostream>
#include <functional> // 必须包含这个头文件来用std::function

// 乘法运算
double multiplyValue(double baseVal, double multiplyBy) {
    return baseVal * multiplyBy;
}

// 除法运算(简单处理除数不为0的情况)
double divideValue(double baseVal, double divideBy) {
    if (divideBy == 0) {
        std::cerr << "Error: Division by zero!\n";
        return 0;
    }
    return baseVal / divideBy;
}

// 减法运算(从基础值中减去参数)
double subtractFromValue(double baseVal, double subtractBy) {
    return baseVal - subtractBy;
}

// 加法运算
double addToValue(double baseVal, double addBy) {
    return baseVal + addBy;
}

第二步:实现运算执行类

这个类会存储基础值,并通过std::function来保存当前要执行的运算逻辑:

class MathOperationExecutor {
private:
    double baseValue_; // 存储基础值
    // 定义运算的函数签名:接收一个操作数,返回运算结果
    std::function<double(double)> currentOperation_;

public:
    // 构造函数初始化基础值
    MathOperationExecutor(double baseVal) : baseValue_(baseVal) {}

    // 设置运算:可以传入任何签名匹配的可调用对象
    void setOperation(std::function<double(double)> op) {
        currentOperation_ = op;
    }

    // 执行运算并返回结果
    double execute(double operand) {
        if (currentOperation_) { // 检查是否已设置运算
            return currentOperation_(operand);
        }
        std::cerr << "Error: No operation set!\n";
        return 0;
    }
};

第三步:使用示例(展示多态行为)

现在我们可以用同一个MathOperationExecutor对象,切换不同的运算,看到不同的执行结果:

int main() {
    // 创建一个基础值为10的运算器
    MathOperationExecutor executor(10.0);

    // 1. 设置乘法运算:用std::bind把基础值绑定到multiplyValue的第一个参数
    executor.setOperation(std::bind(multiplyValue, executor.baseValue_, std::placeholders::_1));
    std::cout << "10 * 5 = " << executor.execute(5.0) << "\n"; // 输出50

    // 2. 切换为除法运算
    executor.setOperation(std::bind(divideValue, executor.baseValue_, std::placeholders::_1));
    std::cout << "10 / 2 = " << executor.execute(2.0) << "\n"; // 输出5

    // 3. 用lambda表达式直接定义运算(更灵活)
    executor.setOperation([thisVal = executor.baseValue_](double operand) {
        return thisVal - operand; // 等价于subtractFromValue
    });
    std::cout << "10 - 3 = " << executor.execute(3.0) << "\n"; // 输出7

    // 4. 直接绑定加法函数
    executor.setOperation(std::bind(addToValue, executor.baseValue_, std::placeholders::_1));
    std::cout << "10 + 4 = " << executor.execute(4.0) << "\n"; // 输出14

    return 0;
}

关键概念拆解

  1. std::function与类型擦除:

    • 不管是普通函数(multiplyValue)、std::bind生成的绑定对象,还是lambda表达式,它们的实际类型都不一样,但std::function<double(double)>能把这些不同类型的可调用对象"擦除"类型差异,只保留调用接口(接收一个double,返回double),所以可以统一存储和调用。
  2. 多态的体现:

    • 同一个executor对象,通过setOperation设置不同的运算逻辑后,调用execute会执行完全不同的行为——这就是运行时多态,不需要依赖类的继承和虚函数,而是通过std::function的类型擦除实现的。
  3. 扩展建议:

    • 你可以尝试自定义仿函数(重载operator()的类),看看能不能也传入setOperation,std::function同样能处理;
    • 试试让运算函数的签名更复杂,比如返回不同类型,看看std::function的灵活性。

内容的提问来源于stack exchange,提问作者Hermes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:36:43