1、函数对象
什么适合推荐使用函数对象?
需要状态的函数调用:
- 需要状态的函数调用:
- 函数对象可以包含成员变量,可以在多次调用中保持状态。这在某些算法中非常有用。
-
提高性能:
- 编译器可以更好地优化函数对象,因为它们是具体的类型,而不是函数指针或 std::function,这减少了间接调用的开销。
- 内联(inline)函数对象的调用可以减少函数调用的开销。
- 灵活的接口:
- 函数对象可以有多个重载或模板版本,以适应不同的调用场景。
- 可以使用模板参数来创建更通用和高效的代码。
-
用于标准库算法:
- 标准模板库(STL)的算法,如
std::sort
,std::find_if
,std::for_each
等,通常需要一个可调用对象作为参数。使用函数对象可以方便地传递复杂的行为。
- 标准模板库(STL)的算法,如
2、自定义函数对象
第二个()为参数
#include <iostream>
using namespace std;
class FunObj
{
public:
void operator()()
{
std::cout << "Hello, World!" << std::endl;
}
void operator()(int n)
{
std::cout << n << std::endl;
}
};
int main() {
FunObj fo;
fo();
fo(1);
// 也可以构造匿名对象FunObj()
FunObj()();
return 0;
}
// 输出
Hello, World!
1
Hello, World!
3、函数对象与容器
#include <iostream>
using namespace std;
#include <map>
int main() {
map<int, string> mapTest;
mapTest.insert(map<int, string>::value_type(1, "aaaa"));
mapTest.insert(map<int, string>::value_type(3, "cccc"));
mapTest.insert(map<int, string>::value_type(2, "bbbb"));
for(map<int, string>::const_iterator it = mapTest.begin(); it != mapTest.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
// 输出
1 aaaa
2 bbbb
3 cccc
从代码中可以看到,是即使我们先插入3,然后再插入2,打印出来却是按照顺序,这是因为map是一个类模板,模板中的第三个参数less是一个结构体,也就是类,里面是一个函数对象,也就是调用这个函数对象来进行比较大小。
template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
class map
{ ...}
// less定义
template<typename _Tp>
struct less : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x < __y; }
};
当然我们也可以用本生提供的greater<>来进行从大到小排序
#include <iostream>
using namespace std;
#include <map>
int main() {
map<int, string, greater<int>> mapTest;
mapTest.insert(map<int, string>::value_type(1, "aaaa"));
mapTest.insert(map<int, string>::value_type(3, "cccc"));
mapTest.insert(map<int, string>::value_type(2, "bbbb"));
for(map<int, string, greater<int>>::const_iterator it = mapTest.begin(); it != mapTest.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
// 输出
3 cccc
2 bbbb
1 aaaa
当然我们也可以自己提供函数对象
#include <iostream>
using namespace std;
#include <map>
struct MyGreater
{
bool operator()(int left, int right) const
{
return left > right;
}
};
int main() {
map<int, string, MyGreater> mapTest;
mapTest.insert(map<int, string>::value_type(1, "aaaa"));
mapTest.insert(map<int, string>::value_type(3, "cccc"));
mapTest.insert(map<int, string>::value_type(2, "bbbb"));
for(map<int, string, MyGreater>::const_iterator it = mapTest.begin(); it != mapTest.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
return 0;
}
// 输出
3 cccc
2 bbbb
1 aaaa
4、函数对象与算法
#include <iostream>
using namespace std;
#include <map>
#include <vector>
#include <algorithm>
void PrintFun(int n)
{
cout << n << ' ';
}
class printObj
{
public:
void operator()(int n)
{
cout << n << ' ';
}
};
void add3(int& n)
{
n += 3;
}
// 函数对象可以记录状态
class addObj
{
public:
addObj(int num) : num_(num)
{
}
void operator()(int& n)
{
n += num_;
}
private:
int num_;
};
class greaterObj
{
public:
greaterObj(int num) : num_(num)
{
}
bool operator()(int n)
{
return n > num_;
}
private:
int num_;
};
int main() {
int a[] = {1, 2, 3, 4, 5};
vector<int> v(a, a + 5);
for_each(v.begin(), v.end(), PrintFun);
cout << endl;
// PrintFun也可以用函数对象实现
for_each(v.begin(), v.end(), printObj());
cout << endl;
for_each(v.begin(), v.end(), add3);
for_each(v.begin(), v.end(), PrintFun);
cout << endl;
// add3也可以用函数对象实现
for_each(v.begin(), v.end(), addObj(10));
for_each(v.begin(), v.end(), PrintFun);
cout << endl;
// 用count_if找到比n大的个数
cout << count_if(a, a + 5, greaterObj(3)) << endl;
return 0;
}
// 输出
1 2 3 4 5
1 2 3 4 5
4 5 6 7 8
14 15 16 17 18
2