1. 为什么需要函数对象
(1)案例
①编写一个函数,使函数可以获得斐波那契数列每项的值。
②每调用一次返回一个值
③函数可根据需要重复使用
【编程实验】第一个解决方案 35-1.cpp
#include <iostream> using namespace std; int fib() { static int a0 = 0; static int a1 = 1; int ret = a1; a1 = a0 + a1; a0 = ret; return ret; } int main() { for(int i = 0; i < 10; i++) { //注意每次调用fib(),形式完全相同,但函数返回的结果不同! //这叫有状态函数,因为函数内部会通过static变量 //记录上次的状态 cout << fib() << endl; //1,1,2,3,5,8,13,21,34,55 } cout << endl; //函数不能回到初始状态,会从新的状态开始,继续计算。 for(int i = 0; i < 5; i++) { cout << fib() << endl; //89,144,233,377,610,从上次结果开始 } return 0; }
运行结果:
(2)存在的问题
①函数一旦开始调用就无法重来(因为这种函数是有状态的函数)
②静态局部变量处理函数内部,外界无法改变
③函数为全局函数,是唯一的,无法多次独立使用
④无法指定某个具体的数列项作为初始值
(3)解决方案:函数对象
①使用具体的类对象取代函数
②该类的对象具备函数调用的行为
③构造函数指定具体的数列项的起始位置
④多个对象相互独立的求解数列项
2. 函数对象
(1)函数调用操作符()
①只能通过类的成员函数重载
②可以定义不同参数的多个重载函数
【编程实验】最终解决方案 35-2.cpp
#include <iostream> using namespace std; class Fib { private: int a0; int a1; public: Fib():a0(0),a1(1){} int operator()() //operator()为函数名,后面的()为参数列表,这里为空 { int ret = a1; a1 = a0 + a1; a0 = ret; return ret; } Fib(int n)//设置初始化 { a0 = 0;//先将初始化a0,a1 a1 = 1; for(int i = 2; i<=n;i++) { int t = a1; a1 = a0 + a1; a0 = t; } } }; int main() { Fib fib; for(int i = 0; i < 10; i++) { //fib是个对象,但因重载操作符(),可以用这个对象名调用函数(重载操作符 //本质上是个函数),这种方式就像函数名调用函数一样直观! cout << fib() << endl; //1,1,2,3,5,8,13,21,34,55 } cout << endl; for(int i = 0; i < 5; i++) { cout << fib() << endl; //89,144,233,377,610,从上次结果开始 } Fib fib2(10);//从第10个元素开始输出 for(int i=0; i<5;i++) { cout << fib2() <<endl; //55,89,144,233,377 } return 0; }
运行结果:
3. 小结
(1)函数调用操作符()是可以重载的
(2)函数调用操作符()只能通过类的成员函数重载
(3)函数调用操作符()可以定义不同参数的多个重载函数
(4)函数对象用于在工程中取代函数指针