一 函数调用运算符 (实际上就是小括号)
我们写一个函数调用,更加直观的理解这个意思
int funcadd(int a, int b) {
return a + b;
}
void funcvoid() {
cout << "funcvoid call" << endl;
}
void main() {
funcadd(1, 2);
funcvoid();
//从上面可以看到,我们调用funcadd函数和funcvoid函数的方法都是给这个函数名后面加上()
// 即使这个funcvoid这个函数不需要任何参数,也是要加上()。
//这里就有一个概念,需要我们记住了,圆括号就是函数调用的明显标记
// ()有个称呼,叫做“函数调用运算符”
}
从上面可以看到,我们调用funcadd函数和funcvoid函数的方法都是给这个函数名后面加上()
// 即使这个funcvoid这个函数不需要任何参数,也是要加上()。
//这里就有一个概念,需要我们记住了,圆括号就是函数调用的明显标记
// ()有个称呼,叫做“函数调用运算符”
二 函数对象/ 仿函数
如果我们在类中重载了 “函数调用运算符”,那么我们就可以像函数一样的使用该类的对象了
一旦该类重载了(),那么该类的对象多了个新名字 “函数对象”
class Teacher9 {
public:
int operator()(int a,int b ) {
return a + b;
}
int operator()(int a) {
return a + 10;
}
bool operator()(int a,double b) {
return a > b;
}
int operator()() {
cout << "operator()()" << endl;
return 100;
}
Teacher9() {
cout << "Teacher9 构造函数被调用"<<endl;
}
};
void main() {
Teacher9 tea;
auto a= tea(2,3);
int b = tea(2);
bool c = tea(2, 1.1);
cout << a << endl;//5
cout << b << endl;//12
cout << c << endl;//1
Teacher9();//这是构造一个临时对象
Teacher9()();//这是构造一个临时对象,然后调用这个临时对象的operator() () 无参数的operator()
cout << "duandian" << endl;
}
三。概念:调用形式相同。
还是以例子解释:
如下的例子中,由于 changestrtoint方法的参数/返回值 和 Teacher10中重载的operator()(string)的参数/返回值相同。
如果两个函数参数一样,返回值一样。这两函数就有了联系,联系是:调用形式相同。
class Teacher10 {
public:
int operator()(string str) {
int x = stoi(str); //stoi 遇到字符会停下来,需要 #include<string>
return x;
}
};
int changestrtoint(string str) {
return 1;
}
四。概念:可调用对象。
如下两个都是可调用对象
changestrtoint 函数 (一般函数)
重载了 函数调用运算符 的类对象
我们现在有个需求,就是将这些可调用对象的指针存储起来,方便以后随时调用,应该怎么弄额?
这里我们首先想到了 函数指针。
但是对于 函数对象,好像都记录不了,那更没办法存储在vector或者list,或者map中了
void main() {
typedef int(*ptype)(string str);
ptype s1 = changestrtoint;
Teacher10 tea;
//ptype s4 = tea;//build error
//ptype s2 = &(Teacher10::operator()); build error
//ptype s3 = Teacher10::operator(); build error
}
我们这里用map储存,但是还是有个问题解决不了,就是怎么存储这个 Teacher 函数对象的实例tea呢?
存储在map中,key存储成int或者string 什么的都可以,只要不重复就行
关键是这个value,需要是 可调用对象的指针。这样表示类型 int(*)(string)
map<int , int(*)(string)>
void main() {
typedef int(*ptype)(string str);
ptype s1 = changestrtoint;
Teacher10 tea;
//ptype s4 = tea;//build error
//ptype s2 = &(Teacher10::operator()); build error
//ptype s3 = Teacher10::operator(); build error
map<int, int(*)(string)> myopr;
myopr.insert(make_pair(1, changestrtoint));
//myopr.insert(make_pair(2, tea));//build error
//因此问题,我们要学习function类模版
}
五。function 类模版介绍:
#include <functional>
function类模版:要提供模版参数来表示该function类型能够表示的“对象的调用形式”。
function<int(string)> //意思是:声明了一个funcation()类型,用来代表一个可调用对象,它所代表的这个可调用对象:接受一个string类型的参数,返回值为int
void main() {
//function<int(string)> ;//意思是:声明了一个funcation()类型,用来代表一个可调用对象,它所代表的这个可调用对象:接受一个string类型的参数,返回值为int
function<int(string)> f1 = changestrtoint;
Teacher10 tea;
function<int(string)> f2 = tea;
//调用一下,结果都是OK的
auto aa = f1("87ui");
cout << aa << endl;
auto bb = f2("87ui");
cout << bb << endl;
map<int, function<int(string)>> myopr;
myopr.insert(make_pair(1,f1));
myopr.insert(make_pair(2, f2));
map<int, function<int(string)>>::iterator it= myopr.find(2);
cout << "(*it).first = " << (*it).first << endl;
function<int(string)> zhizhen = (*it).second;
int res = zhizhen("90k");
cout << res << endl;
}
结果
1
87
(*it).first = 2
90
如果changestrtoint有重载,就无法放入到function里
class Teacher10 {
public:
int operator()(string str) {
int x = stoi(str); //stoi 遇到字符会停下来,需要 #include<string>
return x;
}
};
int changestrtoint(string str) {
return 1;
}
int changestrtoint( ) {
return 2;
}
//如果changestrtoint有重载,就无法放入到function里
void main() {
//function<int(string)> ;//意思是:声明了一个funcation()类型,用来代表一个可调用对象,它所代表的这个可调用对象:接受一个string类型的参数,返回值为int
function<int(string)> f1 = changestrtoint;//这一行build error
Teacher10 tea;
function<int(string)> f2 = tea;
//调用一下,结果都是OK的
auto aa = f1("87ui");
cout << aa << endl;
auto bb = f2("87ui");
cout << bb << endl;
map<int, function<int(string)>> myopr;
myopr.insert(make_pair(1,f1));
myopr.insert(make_pair(2, f2));
map<int, function<int(string)>>::iterator it= myopr.find(2);
cout << "(*it).first = " << (*it).first << endl;
function<int(string)> zhizhen = (*it).second;
int res = zhizhen("90k");
cout << res << endl;
}
如何解决:通过函数指针转一下就OK了
class Teacher10 {
public:
int operator()(string str) {
int x = stoi(str); //stoi 遇到字符会停下来,需要 #include<string>
return x;
}
int operator()() {
int x = 199;
return x;
}
};
int changestrtoint(string str) {
return 1;
}
int changestrtoint( ) {
return 2;
}
//如果changestrtoint有重载,就无法放入到function里
void main() {
//function<int(string)> ;//意思是:声明了一个funcation()类型,用来代表一个可调用对象,它所代表的这个可调用对象:接受一个string类型的参数,返回值为int
//fix 方案
int(*p)(string) = changestrtoint;
function<int(string)> f1 = p;
Teacher10 tea;
function<int(string)> f2 = tea;
//调用一下,结果都是OK的
auto aa = f1("87ui");
cout << aa << endl;
auto bb = f2("87ui");
cout << bb << endl;
map<int, function<int(string)>> myopr;
myopr.insert(make_pair(1,f1));
myopr.insert(make_pair(2, f2));
map<int, function<int(string)>>::iterator it= myopr.find(2);
cout << "(*it).first = " << (*it).first << endl;
function<int(string)> zhizhen = (*it).second;
int res = zhizhen("90k");
cout << res << endl;
}
如果函数对象有重载,则不影响
如下代码是可以正常运行的
class Teacher10 {
public:
int operator()(string str) {
int x = stoi(str); //stoi 遇到字符会停下来,需要 #include<string>
return x;
}
int operator()() {
int x = 199;
return x;
}
};
int changestrtoint(string str) {
return 1;
}
//int changestrtoint( ) {
// return 2;
//}
//如果changestrtoint有重载,就无法放入到function里
void main() {
//function<int(string)> ;//意思是:声明了一个funcation()类型,用来代表一个可调用对象,它所代表的这个可调用对象:接受一个string类型的参数,返回值为int
function<int(string)> f1 = changestrtoint;
Teacher10 tea;
function<int(string)> f2 = tea;
//调用一下,结果都是OK的
auto aa = f1("87ui");
cout << aa << endl;
auto bb = f2("87ui");
cout << bb << endl;
map<int, function<int(string)>> myopr;
myopr.insert(make_pair(1,f1));
myopr.insert(make_pair(2, f2));
map<int, function<int(string)>>::iterator it= myopr.find(2);
cout << "(*it).first = " << (*it).first << endl;
function<int(string)> zhizhen = (*it).second;
int res = zhizhen("90k");
cout << res << endl;
}