C++:函数对象与函数指针

一、函数对象与函数指针

函数对象: 拥有()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;

此时:就是从大到小排序。
在这里插入图片描述

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值