二、仿函数
- 1,定义
- 2,实例
- 3,仿函数的作用
- 3.1,**状态封装(有状态)**
- 3.2,**类型安全(模板友好)**
- 4,与函数的对比
1,定义
什么是仿函数(Functor)?
从字面意思可以猜测是模仿函数的行为使其像函数一样被调用。
具体的定义:
仿函数(Functor)是 C++ 中一种特殊的对象,它通过重载operator()使得对象可以像函数一样被调用。仿函数本质上是类(或结构体)的实例,但提供了函数调用的语法。
2,实例
比如说我们想实现两个整数相加的功能,直接使用加法函数返回结果即可。
而当我们想要使用仿函数时,需要重载operator(),实例化出有名对象,这样调用时就可以模仿函数的调用过程了。
intAdd(intx,inty){returnx+y;}structFunc_Add{intoperator()(inta,intb)const{returna+b;}};intmain(){//Add函数cout<<Add(1,2)<<endl;//仿函数//创建仿函数对象Func_Add f1;cout<<f1(1,2)<<endl;return0;}3,仿函数的作用
在看完上面的例子后,会发现仿函数似乎使用起来比真正的函数还要麻烦,为什么要创造出仿函数呢?或者说仿函数的优点是什么?
3.1,状态封装(有状态)
仿函数可通过成员变量保存调用间的状态
structCounter{intcount=0;voidoperator()(){++count;}};intmain(){Counter c;//初始,c.count = 0cout<<c.count<<endl;c();c();//c.count = 2cout<<c.count<<endl;return0;}3.2,类型安全(模板友好)
在 C++ 中,仿函数可以直接作为模板参数传递,这是其最重要的优势之一。
与函数指针不同,仿函数是一个具体的类型,模板可以根据该类型实例化出对应的版本,编译器因此能够进行完全的内联优化,生成更高效的代码。而传递函数指针时,类型信息被擦除为指针类型,往往难以内联,还可能引入额外的间接调用开销。
#include<iostream>#include<vector>#include<algorithm>// 仿函数:按绝对值大小比较structAbsCompare{booloperator()(inta,intb)const{returnabs(a)<abs(b);}};intmain(){std::vector<int>v={3,-1,2,-5,4};// 直接将仿函数类型传递给模板,编译器能生成针对 AbsCompare 的特化版本sort(v.begin(),v.end(),AbsCompare());// 输出:-1 2 3 4 -5for(intx:v){cout<<x<<" ";}return0;}4,与函数的对比
| 特性 | 普通函数 | 仿函数 |
|---|---|---|
| 状态 | 无状态(只能通过全局/静态变量保存额外信息) | 有状态,可通过成员变量在调用间保存数据 |
| 内联优化 | 函数指针传递时难以内联;直接调用可内联 | 作为模板参数时类型确定,极易内联 |
| 模板参数传递 | 必须退化为函数指针,类型信息被擦除 | 保留完整类型,模板可生成专属实例 |
| 多态/扩展性 | 只能靠重载,不能携带额外上下文 | 可通过继承实现运行时多态(配合虚函数),也可组合多个仿函数 |
| 语法简洁性 | 定义简单,调用自然 | 需定义类并重载operator(),稍显繁琐(C++11 lambda 为此提供了语法糖) |
| 典型应用 | 简单固定功能的操作 | 自定义排序准则、状态回调、函数对象适配器等 |