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,字符串可以使用字符串類而不用字符數組,數組可以使用數組對象,函數指針可以用函數對象,這些對象都是用於在工程中取代指針;