文章目录
一、函数对象与函数指针
函数对象: 拥有()operator重载函数的对象即函数对象,函数对象类似C语言里面的函数指针,但在C++里为函数对象。
问题一:什么是函数对象呢?
例如:我们C语言进行函数调用与C++中两个函数调用。
看起来它们好像一模一样,但是C语言中的sum(),是函数名为一个地址;但C++中的sum()为一个对象,sum调用自己的()重载函数将10与20传给sum调用的()运算符重载函数了,它接受两个实参,再执行a+b。
这里我们就把()运算符重载函数的对象,称作函数对象,或者称作仿函数。
问题二:那么使用函数对象有什么好处呢?
我们来瞧一瞧:
template<typename T>
bool compare(T a, T b)
{
return a > b;
}
int main()
{
cout << compare(10, 20) << endl;
cout << compare('b','y') << endl;
return 0;
}
我里我们实现了一个比较大于的函数模板,这里我们编译器会根据实参推导出T的类型,再从原模板实例化处理整型与char类型的compare()函数。
但是它不够灵活,我们有时想比较小于,每次改动符号有些麻烦,C语言中的函数指针刚好可以很好解决这个问题。
使用C语言中函数指针解决:
//使用C的函数指针解决
template<typename T>
bool mygreater(T a, T b)
{
return a > b;
}
template<typename T>
bool myless(T a, T b)
{
return a < b;
}
//compare是C++的库函数模板
template<typename T, typename Compare>
bool compare(T a, T b, Compare comp)
{
return comp(a, b);
}
int main()
{
cout << compare(10, 20,mygreater<int>) << endl;
cout << compare(10, 20,myless<int>) << endl;
return 0;
}
成功执行:
此时,就可以很好的解决这个问题了,我们传入不同的函数指针来解决,想比较大就传入mygreater,想比较小就传入myless,通过函数指针间接调用函数;
但是这里,我们通过函数指针虽然解决了问题,但函数指针无法进行内联,有函数的调用开销,效率很低;即使将其能够写为内联函数,编译的时候还是不知道调用时mygreater,myless。这里是通过函数指针间接调用的,编译器在编译过程中看到函数指针时候,不知道其调用的哪个函数,只有运行时候才知道。因此,C++有一个专门的函数对象来解决这个问题。
使用C++中函数对象解决:
好处:
1.通过函数对象调用()运算符重载,可以省略函数的调用开销,比通过函数指针调用函数(不能内联调用)效率高。
2.因为函数对象是用类生成的,所以可以添加相关的成员变量用来记录函数对象使用时更多的信息。
//C++函数对象实现
template<typename T>
class mygreater
{
public:
bool operator()(T a, T b)//二元函数对象
{
return a > b;
}
};
template<typename T>
class myless
{
public:
bool operator()(T a, T b)//二元函数对象
{
return a < b;
}
};
//compare是C++的库函数模板
template<typename T, typename Compare>
bool compare(T a, T b, Compare comp)
{
return comp(a, b);//编译过程知道调用对象的函数operator()(a, b);
}
int main()
{
cout << compare(10, 20,mygreater<int>()) << endl;
cout << compare(10, 20,myless<int>()) << endl;
return 0;
}
执行成功:函数对象相比于函数指针效率更高。
二、使用实例
实例1:优先级队列
我们的优先级队列,底层依赖vector容器,底层默认为一个大根堆。
int main()
{
priority_queue<int> que;//底层vector
for (int i=0; i<10; ++i)//大根堆
{
que.push(rand() % 100);
}
while (!que.empty())
{
cout << que.top() << " ";
que.pop();
}
cout << endl;
return 0;
}
打印一下:堆顶元素最大。
如果我们想用小根堆如何做呢?
只是库中的实现:
template<class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type> >
我们将less改为greater即可变为小根堆即可。
using MinHeap = priority_queue<int, vector<int>, greater<int>>;
实例2:set
set底层为红黑树,默认底层从小到大进行输出。底层为:
template<class _Kty,
class _Pr = less<_Kty>,
class _Alloc = allocator<_Kty> >
若想将底层排序方式改变:可以将less改变即可。
set<int, greater<int>> set;
for (int i=0; i<10; ++i)
{
set.insert(rand() % 100);
}
for (int v : set)
{
cout << v << " ";
}
cout << endl;
此时:就是从大到小排序。