一、函数调用运算符
1、圆括号()就是函数调用的明显标记,()有一个称呼叫做“函数调用运算符”;
2、如果我在类中重载了函数调用运算符,那么我们就可以像使用函数一样使用该类的对象了。对象(实参):
class BiggerThanZero
{
public:
//重载圆括号(函数调用运算符)
int operator()(int value) const
{
if (value < 0)
return 0;
return value;
}
};
int main()
{
int i = 200;
BiggerThanZero obj;
int result = obj(i);//等价于obj.operator()(i);
//int result = obj.operator()(i);
cout << result << endl;
return 0;
}
2、对象(实参)有点似曾相识,那就是有参构造函数:
class BiggerThanZero
{
public:
//重载圆括号(函数调用运算符)
BiggerThanZero(int i){};//有参构造函数
int operator()(int value) const
{
if (value < 0)
return 0;
return value;
}
};
int main()
{
int i = 200;
BiggerThanZero obj(i);//这是对象定义并初始化,所以调用的是构造函数,并没有调用重载的()
int result = obj(i);//等价于obj.operator()(i);
//int result = obj.operator()(i);
cout << result << endl;
return 0;
}
3、结论:
1)只要这个对象所属的类重载了()(函数调用运算符),那么这个类对象就变成了可调用的勒,而且可以调用多个版本的(),只要在参数类型或者数量上有差别即可;
class BiggerThanZero
{
public:
//重载圆括号(函数调用运算符)
BiggerThanZero(int i){};//有参构造函数
int operator()(int value) const //重载() 1
{
if (value < 0)
return 0;
return value;
}
int operator()(int value, char c) const//重载() 2
{
if (value < 0)
return 0;
return value;
}
int operator()(int value, char c, int value1) const//重载() 3
{
if (c < 0)
return 0;
return c;
}
};
2)这个类重载了(),那么该类的对象就多了个新名字,叫“函数对象”,因为可以调用这种对象。或者换一种说法:这些对象的行为像函数一样;
4、不同调用对象的相同调用形式(如下echoValue函数与BiggerThanZero类中的operator()就叫做调用形式相同):
class BiggerThanZero
{
public:
int operator=(int value) const
{
cout << "class value : " << value << endl;
if(value < 0)
return 0;
return value;
}
};
int echoValue(int value)//调用参数和返回值与BiggerThanZero类中的operator()成员相同
{
cout << "echoValue : " << value << endl;
if(value < 0)
return 0;
return value;
}
1)函数echoValue和类BiggerThanZero的重载(),这两个东西的调用参数和返回值相同,我们可以称之为“调用形式相同”;
2)一种调用形式对应一个函数类型,如int(int) 表示接受一个int参数和返回一个int值;
5、可调用对象
1)如下两种实现都是可调用对象:
a)echoValue函数;
b)重载了函数调用运算符的BiggerThanZero类对象;
2)把这些可调用对象的指针保存起来,目的是方便我们随时调用这些“可调用对象”,这些指针感觉像我们C语言中的函数指针;
int (*p)(int x);//p就是定义的指针变量
p = max;//函数max的入口地址给p
int result = p(5);//调用函数max 等价于 max(5);
三、标准库map类型介绍
1、map是一个类模板,头文件#include <map>;
2、Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据 处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
3、map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。
对于迭代器来说,可以修改实值,而不能修改key。
4、用法:
map<int, string> mapStudent;
5、数据的插入:
1)用insert函数插入pair数据
//数据的插入--第一种:用insert函数插入pair数据
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, "student_one"));
mapStudent.insert(pair<int, string>(2, "student_two"));
mapStudent.insert(pair<int, string>(3, "student_three"));
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout<<iter->first<<' '<<iter->second<<endl;
return 0;
}
2)用insert函数插入value_type数据:
//第二种:用insert函数插入value_type数据,下面举例说明
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int, string> mapStudent;
mapStudent.insert(map<int, string>::value_type (1, "student_one"));
mapStudent.insert(map<int, string>::value_type (2, "student_two"));
mapStudent.insert(map<int, string>::value_type (3, "student_three"));
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout<<iter->first<<' '<<iter->second<<endl;
return 0;
}
3)用数组方式插入数据:
//第三种:用数组方式插入数据,下面举例说明
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int, string> mapStudent;
mapStudent[1] = "student_one";
mapStudent[2] = "student_two";
mapStudent[3] = "student_three";
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout<<iter->first<<' '<<iter->second<<endl;
return 0;
}
6、注意:以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的,当然了第一种和第二种在效果上是完成一样的,用insert函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对 应的值;
7、参考博客:C++ STL 中 map 容器的说明和使用技巧;
四、标准库function类型介绍
1、function是一个类模板,头文件#include <functional>;
2、function类模板,要提供模板参数来表示该function类型能够表示的“对象的调用形式”,类模板std :: function是一个通用的多态函数包装器, std :: function的实例可以存储,复制和调用任何可调用的目标 :包括函数,lambda表达式,绑定表达式或其他函数对象,以及指向成员函数和指向数据成员的指针。当std::function对象未包裹任何实际的可调用元素,调用该std::function对象将抛出std::bad_function_call异常;
template< class R, class... Args >
class function<R(Args...)>;
模板参数说明:
R: 被调用函数的返回类型
Args…:被调用函数的形参
function<int(int)>//声明了一个function()类型,用来代表一个可调用对象,它所代表的这个可调
//用对象是:接受一个int参数,返回一个int类型;
五、可调用对象的使用
class BiggerThanZero
{
public:
int operator=(int value) const
{
cout << "class value : " << value << endl;
if(value < 0)
return 0;
return value;
}
};
int echoValue(int value)//调用参数和返回值与BiggerThanZero类中的operator()成员相同
{
cout << "echoValue : " << value << endl;
if(value < 0)
return 0;
return value;
}
int main()
{
map<string, function<int(int)>> myoper = {
{"a1", echoValue},
{"a2", obj},
{"a3", BiggerThanZero}
};
myoper["a1"](12);//调用echoValue函数
myoper["a2"](13);//调用obj对象的operator()函数
myoper["a3"](14);//调用BiggerThanZero类重载()函数
return 0;
}
1、一旦function遇到echoValue的重载版本就无法识别,编译不通过;
int echoValue(int value)//调用参数和返回值与BiggerThanZero类中的operator()成员相同
{
cout << "echoValue : " << value << endl;
if(value < 0)
return 0;
return value;
}
int echoValue()
{
return 1;
}
int main()
{
map<string, function<int(int)>> myoper = {
{"a1", echoValue};//编译报错
};
return 0;
}
解决:我们可以通过定义函数指针类解决,如下:
int (*fp)(int) = echoValue;
int (*fp1)() = echoValue;