3.14.1函数对象
函数对象英文为function object,有时也称为“仿函数(functor)”。综合这两种叫法可以得出它的主要作用,即用一个对象来模拟一个函数
还记得vector的"[ ]"操作符吗?,C++允许把操作符当成一个函数来设计。比如vector类型中,其实存在了一个名为"operator[ ]"的成员函数。
我们还说
manyBeauties[0]
其实相当于:
manyBeauties.operator[](0)
今天我们要“设计”的操作符是方括号的兄弟圆括号"()"。假设有一个表示狗狗的类型Dog,它存在一个成员函数Bark:
struct Dog
{
void Bark() const
{
cout << "Wang~Wang~" << endl; //汪星人
}
};
既然强大的C++允许我们用“操作符”来作为函数的名字,"()"也是一种操作符,因此我想用它来替换Bark,于是将上述代码中的“Bark”字样替换成“()”:
struct Dog
{
void ()() const//噢,这是什么?ERROR!
{
cout << "Wang~Wang~" << endl;
}
};
003行看上去像火星文,也编译不了。或许纯粹就是为了让代码看起来正经一点吧,C++语法规定操作符函数的正确语法是函数名称前必须加上“operator”:
struct Dog
{
void operator()() const//operator()是一个成员函数
{
cout << "Wang~Wang~" << endl;
}
};
这一次正确了,虽然看起来还是很奇怪呢。接下来如何使用这个函数呢?根据之前“operator[ ]”的经验,我们可以很快得出,使用方法有两种:
Dog doggie;
doggie.operator()();//方法一
doggie();//方法二
请看003行,003行的代码好像是调用一个名为"doggie"的函数,可是再看001行,doggie它明明是一个变量,明明是一个数据,明明是一个对象啊!这就是C++语言在这里玩的一个语法游戏,一个“障眼法”。
假象:
doggie();//调用一个函数,函数名:doggie
真相:
doggie();//通过doggie调用一个成员函数,函数名:operator()
//doggie是一个对象,即:doggie.operator()
doggie是001行定义的一个类型为Dog的对象,而"()"是他的一个成员函数。
是一个函数?还是一个对象?原来是一个对象在调用一个函数,一个叫做“operator()”的函数。
所以,要使用函数对象,必须有一个对象,该对象类型内部完成了对"()"的重载,
调用语法格式为:对象(), ()表示对象调用自己的成员函数operator(),加上(),表示完成了对 对象的成员函数operator()的调用。
完整代码:
28行,doggie是一个类型为Dog的对象,而“()”是它的一个成员函数,doggie()实际上是doggie.operator()
所以函数对象,就是一个对象在调用一个函数,一个叫做"operator()"的函数
"operator()"既然是函数,那就可以有参数,也可以有返回值
代码解释:
53行,定义了一个Totaliser对象total;
54行,total(1)就是调用“total.operator()(1)”,_base将在0的基础上自加1,从而变成1;
55行,total()就是调用“total.operator()()”,返回值1被输出到屏幕
56行,total(2)就是调用"total.operator()(2)",_base将在1的基础上自加2,变成3;
57行,total()就是调用“total.operator()()”,返回值3被输出到屏幕
运行结果为: