1,本博文讲述函数对象问题;
2,客户需求:
1,编写一个函数:
1,函数可以获得斐波那契数列每项的值;
2,每调用一次返回一个值;
3,函数可根据需要重复使用;
4,代码示例:
1 for(int i=0; i<10; i++) 2 { 3 cout << fib() << endl; 4 }
3,第一个解决方案编程实验:
1,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 int fib() 7 { 8 static int a0 = 0; // 记录函数状态; 9 static int a1 = 1; 10 11 int ret = a1; 12 13 a1 = a0 + a1; // 更新 a1 的值; 14 a0 = ret; // a0 更新; 15 16 return ret; 17 } 18 19 20 int main() 21 { 22 for(int i=0; i<5; i++) 23 { 24 cout << fib() << endl; //fib() 是带状态的函数,因为每次调用的结果是不同的,当输入的参数是一样的,返回结果必然是一样的函数叫做无状态函数; 25 } 26 27 cout << endl; 28 29 for(int i=0; i<5; i++) 30 { 31 cout << fib() << endl; 32 } 33 34 return 0; 35 }
2,输出结果:
1 1 2 1 3 2 4 3 5 5 6 7 8 8 13 9 21 10 34 11 55
3,带状态函数:每次调用的返回结果不同的函数,即相同的输入参数,不同的返回结果;
4,两种方法实现带状态函数:
1,是将函数内部要使用的变量用全局变量来代替,可以记录上一次函数调用的状态,但是代码中建议不要使用全局变量;
2,是将函数内部要使用的变量用静态局部变量来代替;
4,存在的问题:
1,函数一旦开始调用就无法重来:
1,静态局部变量处于函数内部,外界无法改变;
2,函数为全局函数,是唯一的,无法多次独立使用;
3,无法指定某个具体的数列项作为初始值;
2,当用全局变量来使用时,可以达到目的,但是要在调用函数之前设置全局变量初始值,这样和用户的要求不符合;
5,解决方案:
1,函数对象:
1,使用具体的类对象取代函数;
2,该类的对象具备函数调用的行为;
1,很了不起的行为;
3,构造函数指定具体数列项的起始位置;
4,多个对象相互独立的求解数据项;
6,函数对象:
1,函数调用操作符(()):
1,只能通过类的成员函数重载;
2,可以定义不同参数的多个重载函数;
(3),C 和 C++ 中,函数调用操作符 “()” 其实是编译器内置的操作符,它的地位同 “[]” 一致,可以被重载,重载后一个类的对象可以当做 函数来使用;
7,最终解决方案编程实验:
1,main.cpp 文件:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Fib 7 { 8 int a0; 9 int a1; 10 public: 11 Fib() 12 { 13 a0 = 0; 14 a1 = 1; 15 } 16 17 /* 这个函数实现的非常经典 */ 18 Fib(int n) 19 { 20 a0 = 0; 21 a1 = 1; 22 23 for(int i=2; i<=n; i++) 24 { 25 int t = a1; 26 27 a1 = a0 + a1; 28 a0 = t; 29 } 30 } 31 32 int operator () () // 重载函数调用操作符 (),这样类的对象就可以当做函数来调用; 33 { 34 int ret = a1; 35 36 a1 = a0 + a1; 37 a0 = ret; 38 39 return ret; 40 } 41 }; 42 43 int main() 44 { 45 Fib fib; 46 47 for(int i=0; i<10; i++) 48 { 49 cout << fib() << endl; // fib 不是函数名,而是对象名,这里将对象当做函数调用; 50 } 51 52 cout << endl; 53 54 for(int i=0; i<5; i++) 55 { 56 cout << fib() << endl; 57 } 58 59 cout << endl; 60 61 Fib fib2(10); // 第二个对象和第一个独立,也就可以从头开始了; 62 63 for(int i=0; i<5; i++) 64 { 65 cout << fib2() << endl; 66 } 67 68 return 0; 69 }
2,输出结果:
1 1 2 1 3 2 4 3 5 5 6 7 8 8 13 9 21 10 34 11 55 12 13 5 14 8 15 13 16 21 17 34
3,提供函数对象,通过私有成员变量来记录函数调用状态,意味着绕开了局部 变量和全局变量这样的限制;
4,带状态函数实现方法:
1,用全局变量实现函数内部的使用变量;
2,静态局部变量;
3,函数对象中的成员变量;
8,小结:
1,函数调用操作符(())是可重载的;
2,函数调用操作符只能通过类的成员函数重载;
1,和 “=” 相同;
3,函数调用操作符可以定义不同参数的多个重载函数;
4,函数对象用于在工程中取代函数指针;
1,实际的 C++ 工程项目中,我们要尽量少的使用原生的指针;
2,字符串可以使用字符串类而不用字符数组,数组可以使用数组对象,函数指针可以用函数对象,这些对象都是用于在工程中取代指针;