实例代码:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <functional>
using namespace std;
void func(int i){
cout << "这是函数func()" << endl;
return;
}
//下面类重载()运算符
//如果值 < 0,那么就返回0,否则返回实际的值
class biggerthanzero{
public:
//重载圆括号(函数调用运算符)
int operator()(int value) const{
if (value < 0)
return 1;
return value;
}
};
class biggerthanzero1{
public:
biggerthanzero1(int){
cout << "bigg...构造函数执行了" << endl;
}
//重载圆括号(函数调用运算符)
int operator()(int value) const{
if (value < 0)
return 1;
return value;
}
//重载圆括号(函数调用运算符)
int operator()(int value, int value1) const{
return 1;
}
};
//普通函数:打印value值并原样返回
int echobvalue(int value) { //调用参数和返回值与biggerthanzero1中的operator()相同
cout << value << endl;
return value;
}
int echobvalue1(int value) { //调用参数和返回值与biggerthanzero1中的operator()相同
cout << value << endl;
return value;
}
int echobvalue1() { //调用参数和返回值与biggerthanzero1中的operator()相同
return 1;
}
int main() {
//一:学习C++体会
//(1) 对语言本身的学习
//(2) 大量练习
//(3) 开始阅读优秀的人写的优秀代码
func(5);
//圆括号()就是函数调用的明显标记,()有一个称呼叫做“函数调用运算符”;
//如果我在类中重载了函数调用运算符(),那么我就可以像使用函数一样使用该类的对象了。如:“ 对象(实参)” 这种形式
//如何使用类中重载了函数调用运算符()的类呢?
//(a) 定义一个该类对象
//(b) 像函数调用一样使用该对象,也就是()中增加实参列表。
int i = 200;
biggerthanzero obj; //含有函数调用运算符的对象。
int result = obj(i); //等价于调用obj.operator()(i);
//int result1 = obj.operator()(i); // 和上面的语句等价
biggerthanzero1 obj1(5);//注意:这是对象定义并初始化,所以调用的是构造函数
obj1(2); //这里已经初始化过了,调用的是对象obj的()圆括号。
//只要这个对象所属的类重载了()“函数调用运算符”,那么这个类对象就变成了可调用的了,
//而且可以调用多个版本的(),只要在参数类型或者数量上有差别即可,即重载。如下面:
obj1(5, 6); //调用含有两个参数的对象obj的()圆括号
//这个类重载了(),那么该类的对象多了个新名字:“函数对象”,因为可以调用这种对象
//或者换一种说法,这些对象的行为像函数一样。
//二: 不同调用对象的相同调用形式
//函数echobvalue和类 biggerthanzero 的重载的(),这两个东西,调用参数和返回值相同,就叫做“调用形式相同”
//一种调用形式 对应 一个函数类型: int(int);
// 函数类型:int(int) //表示接受一个int参数,返回一个int值
//引入概念叫 “可调用对象”,如下两个都是可调用对象。
//a) echobvalue函数。
//b) 重载了函数调用运算符的biggerthanzero类对象。
//把这些可调用对象的指针保存起来,目的是方便我们随时调用这些“可调用对象”,这些指针类似
//C语言中的函数指针。
//那么我们可以用map 这种键值对数据类型,键存放“标识”,值存放“函数指针”,如下:
//"add", 0x123
//"red", 0x456
map<string, int(*)(int) > myoper;
myoper.insert({ "ev", echobvalue }); //用insert方法往这个容器中增加了一项,键值对。
biggerthanzero obj2;
//myoper.insert({ "bt", biggerthanzero });
//myoper.insert({ "ev", obj2 });
//上面两种方式都不可以,标准库引入一个新的概念"function" 解决这个问题
//三、标准库function类型介绍
//function 类模板,要提供模板参数来表示该function类型能够表示的“对象的调用形式”。
//function<int(int)> //这就叫 声明了一个function()类型,用来代表一个可调用对象,它所代表的这个可调用对象是:
//接受一个int参数,返回的也是一个int类型,
function<int(int)> f1 = echobvalue; //函数指针
function<int(int)> f2 = obj2; //类对象,因为类中有()重载
function<int(int)> f3 = biggerthanzero(); //用类名生成一个对象,也可以,因为类中有()重载。
//调用
f1(5);// 5
cout << f2(3) << endl; //3
cout << f3(-5) << endl; //0
//下面就可以在map中存放function类型 从而解决上面的 存储调用函数指针问题
map<string, function<int(int)>> myoper1 = {
{ "ev", echobvalue },
{ "bt", obj2 },
{ "bt2", biggerthanzero() }
};
myoper1["ev"](12); //就是调用echobvalue 函数 输出:12
cout << myoper1["bt"](3) << endl; //调用obj对象的()操作符 输出:3
cout << myoper1["bt2"](-5) << endl; //调用biggerthanzero类对象的()操作符 输出:0
//function<int(int)> f1 = echobvalue1;//注意 如果echobvalue 函数重载了,就无法放到function<>类型的对象中, function不能识别到底使用哪个echobvalue函数,会提示错误
//上面的问题,我们可以通过定义函数指针来解决
int(*fp1)(int) = echobvalue1; //定义函数指针,在重载情况下,不会产生二义性,因为函数指针里有对应的参数类型和返回类型。
int(*fp2)() = echobvalue1;
int(*fp3)(int) = echobvalue1;
function<int(int)> ff1 = fp1; //直接赋函数指针,而不是函数名echobvalue1
function<int()> ff2 = fp2;
function<int(int)> ff3 = fp3;
ff1(3);
cout << ff2() << endl;
ff3(3);
system("pause");
return 0;
}