新手技术问询:如何用带不同方法签名的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; }
关键概念拆解
std::function与类型擦除:
- 不管是普通函数(
multiplyValue)、std::bind生成的绑定对象,还是lambda表达式,它们的实际类型都不一样,但std::function<double(double)>能把这些不同类型的可调用对象"擦除"类型差异,只保留调用接口(接收一个double,返回double),所以可以统一存储和调用。
- 不管是普通函数(
多态的体现:
- 同一个
executor对象,通过setOperation设置不同的运算逻辑后,调用execute会执行完全不同的行为——这就是运行时多态,不需要依赖类的继承和虚函数,而是通过std::function的类型擦除实现的。
- 同一个
扩展建议:
- 你可以尝试自定义仿函数(重载
operator()的类),看看能不能也传入setOperation,std::function同样能处理; - 试试让运算函数的签名更复杂,比如返回不同类型,看看
std::function的灵活性。
- 你可以尝试自定义仿函数(重载
内容的提问来源于stack exchange,提问作者Hermes
相关产品推荐
相关产品推荐

