c++仿函数及在STL中的应用
1 仿函数
1.1 前置知识
1.1.1 运算符重载
作用:实现两个自定义数据类型(比如两个结构体/类 相加)“相加” 的运算。
????????可以认为,运算符重载的实质是编写以? “opertor 运算符”? 作为名称的函数。运算符函数的语法格式如下:
返回值类型 operator运算符(形参表)
{
....
}
下面是“+”运算符重载的例子:
class Person {
public:
Person() {};
Person(int a, int b)
{
this->m_A = a;
this->m_B = b;
}
//成员函数实现 + 号运算符重载
Person operator+(const Person& p) {
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
public:
int m_A;
int m_B;
};
//全局函数实现 + 号运算符重载
//Person operator+(const Person& p1, const Person& p2) {
// Person temp(0, 0);
// temp.m_A = p1.m_A + p2.m_A;
// temp.m_B = p1.m_B + p2.m_B;
// return temp;
//}
//运算符重载 可以发生函数重载
Person operator+(const Person& p2, int val)
{
Person temp;
temp.m_A = p2.m_A + val;
temp.m_B = p2.m_B + val;
return temp;
}
void test() {
Person p1(10, 10);
Person p2(20, 20);
//成员函数方式
Person p3 = p2 + p1; //相当于 p2.operaor+(p1)
cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl;
Person p4 = p3 + 10; //相当于 operator+(p3,10)
cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl;
}
int main() {
test();
system("pause");
return 0;
}
? ? ? ? 实际上,一个普通函数,定义好入参,也可以实现?两个自定义数据类型(比如两个结构体/类 相加)“相加” 的运算;和“运算符重载函数”的区别就是?运算符重载函数的调用可以很自然,可以直接用 A+ B 的方式,潜移默化的调用运算符重载函数。
PS:我们可以直接用全局函数实现一个 运算符重载,也可以将运算符重载写在一个类里作为成员函数。
1.1.2?函数调用运算符 “()” 重载
类似于加号运算符重载,函数调用运算符 “()” 也可以重载。
class MyPrint
{
public:
void operator()(string text) //operator() 是函数名
{
cout << text << endl;
}
};
void test01()
{
//重载的()操作符 也称为仿函数
MyPrint myFunc;
myFunc("hello world");
}
int main() {
test01();
system("pause");
return 0;
}
1.1.3 函数对象(仿函数)
????????一句话:重载?函数调用操作符()的类的对象,称为函数对象。(例如,1.1.2小节中的 myFunc 、add 其实都是函数对象。)
? ? ? ? 由于函数对象的使用非常像函数的调用,因此函数对象又称为仿函数。
????????函数对象(仿函数)实现了把一个函数像一个对象一样去使用(作为参数传递、也可以有成员变量),把一个对象像一个函数一样去使用(对象可以像函数一样调用),功能很强大轻便。如下示例:
#include <string>
//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
public :
int operator()(int v1,int v2)
{
return v1 + v2;
}
};
void test01()
{
MyAdd myAdd;
cout << myAdd(10, 10) << endl;
}
//2、函数对象可以有自己的状态。我们可以记录这个函数调用了多少次(想像如果是普通函数调用次数,就需要一个全局变量);
class MyPrint
{
public:
MyPrint()
{
count = 0;
}
void operator()(string test)
{
cout << test << endl;
count++; //统计使用次数
}
int count; //内部自己的状态
};
void test02()
{
MyPrint myPrint;
myPrint("hello world");
myPrint("hello world");
myPrint("hello world");
cout << "myPrint调用次数为: " << myPrint.count << endl;
}
//3、函数对象可以作为参数传递
void doPrint(MyPrint &mp , string test)
{
mp(test);
}
void test03()
{
MyPrint myPrint;
doPrint(myPrint, "Hello C++");
}
int main() {
//test01();
//test02();
test03();
system("pause");
return 0;
}
匿名函数对象(仿函数)
????????在函数对象像函数一样调用的过程中,有时候我们只关心两个操作数的运算,这样先定义一个函数对象,再用这个对象去调用其运算符函数,就显得稍微缓慢。为了轻便简洁使用,发明了?匿名函数对象。
? ? ? ? 观察下面例子:为了实现两个数(可以是自定义数据类型)相加,方式1就是一个普通函数对象调用其运算符函数实例;方式2??则不是先起一个 函数对象名 add,然后再用add调用;而是直接用类型名MyAdd加一个()的方式临时表示一个‘函匿名数对象’,后面直接跟参数(如果没入参,可省略),就达到了我们的目的。这样的函数对象用完即释放,这样写很方便。
class MyAdd
{
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
void test()
{ //方式1:
MyAdd add;
int ret = add(10, 10);
cout << "ret = " << ret << endl;
//方式2:
cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}
1.1.4 谓词
返回bool类型的仿函数称为谓词
如果operator()接受一个参数,那么叫做一元谓词
如果operator()接受两个参数,那么叫做二元谓词
?一元谓词示例--仿函数在STL算法库 std::find_if 中的应用:
#include <vector>
#include <algorithm>
//1.一元谓词
struct GreaterFive{
bool operator()(int val) {
return val > 5;
}
};
void test01() {
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it == v.end()) {
cout << "没找到!" << endl;
}
else {
cout << "找到:" << *it << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
观察上面 std::find_if()函数的调用,我们先回顾 find_if()函数原型,
1.std::find_if()函数功能:按条件查找元素
2.函数原型
find_if( iterator beg, iterator end, _pred)
按值查找元素,找到的话返回指定位置的迭代器,找不到则返回结束迭代器位置
beg :开始迭代器
end :结束迭代器
_pred :函数或者谓词 (返回bool类型的仿函数)
?find_if()函数的参3需要传入一个谓词,我们传入了一个匿名函数对象(当然也可以自己定义一个实名函数对象传入),其也是个一元谓词。
二元谓词示例--仿函数在STL算法库 std::sort 中的应用:
#include <vector>
#include <algorithm>
//二元谓词
class MyCompare
{
public:
bool operator()(int num1, int num2)
{
return num1 > num2;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(30);
v.push_back(50);
//默认从小到大
sort(v.begin(), v.end());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
cout << "----------------------------" << endl;
//使用函数对象改变算法策略,排序从大到小
sort(v.begin(), v.end(), MyCompare());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
上面两个 STL 算法都是使用比较频繁的,因此要熟悉其内在应用逻辑。?
2 仿函数在STL中的其他应用
STL内建函数对象(仿函数):
头文件
#include<functional>
算术仿函数
仿函数原型: template<class T> T plus<T> //加法仿函数 template<class T> T minus<T> //减法仿函数 template<class T> T multiplies<T> //乘法仿函数 template<class T> T divides<T> //除法仿函数 template<class T> T modulus<T> //取模仿函数 template<class T> T negate<T> //取反仿函数
关系仿函数
template<class T> bool equal_to<T> //等于 template<class T> bool not_equal_to<T> //不等于 template<class T> bool greater<T> //大于== template<class T> bool greater_equal<T> //大于等于 template<class T> bool less<T> //小于 template<class T> bool less_equal<T> //小于等于
逻辑仿函数
template<class T> bool logical_and<T>` //逻辑与 template<class T> bool logical_or<T>` //逻辑或 template<class T> bool logical_not<T>` //逻辑非
?这里我们只举例介绍一个在STL中的应用常用的内建函数对象:greater
????????头文件<functional>中已经建立好的仿函数
greater(),让我们在使用sort从大到小排序的时候不用每次都自己写一个仿函数 mycompare():
#include <functional>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
bool operator()(int v1,int v2)
{
return v1 > v2;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(40);
v.push_back(20);
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数 大于仿函数
sort(v.begin(), v.end(), greater<int>());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!