C++程序設計(譚潔強)第4章_第1頁
C++程序設計(譚潔強)第4章_第2頁
C++程序設計(譚潔強)第4章_第3頁
C++程序設計(譚潔強)第4章_第4頁
C++程序設計(譚潔強)第4章_第5頁
已閱讀5頁,還剩185頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第第4章章 函數與預處理函數與預處理4.1 概述概述4.2 定義函數的一般形式定義函數的一般形式4.3 函數參數和函數的值函數參數和函數的值4.4 函數的調用函數的調用*4.5 內置函數內置函數*4.6 函數的重載函數的重載*4.7 函數模板函數模板*4.8 有默認參數的函數有默認參數的函數4.9 函數的嵌套調用函數的嵌套調用4.10 函數的遞歸調用函數的遞歸調用4.11 局部變量和全局變量局部變量和全局變量4.12 變量的存儲類別變量的存儲類別4.13 變量屬性小結變量屬性小結4.14 關于變量的聲明和定義關于變量的聲明和定義4.15 內部函數和外部函數內部函數和外部函數4.16 預處理命令

2、預處理命令一個較大的程序不可能完全由一個人從頭至尾地完一個較大的程序不可能完全由一個人從頭至尾地完成,更不可能把所有的內容都放在一個主函數中。成,更不可能把所有的內容都放在一個主函數中。為了便于規劃、組織、編程和調試,一般的做法是為了便于規劃、組織、編程和調試,一般的做法是把一個大的程序劃分為若干個程序模塊把一個大的程序劃分為若干個程序模塊(即程序文即程序文件件),每一個模塊實現一部分功能。不同的程序模,每一個模塊實現一部分功能。不同的程序模塊可以由不同的人來完成。在程序進行編譯時,以塊可以由不同的人來完成。在程序進行編譯時,以程序模塊為編譯單位,即分別對每一個編譯單位進程序模塊為編譯單位,即

3、分別對每一個編譯單位進行編譯。如果發現錯誤,可以在本程序模塊范圍內行編譯。如果發現錯誤,可以在本程序模塊范圍內查錯并改正。在分別通過編譯后,才進行連接,把查錯并改正。在分別通過編譯后,才進行連接,把各模塊的目標文件以及系統文件連接在一起形成可各模塊的目標文件以及系統文件連接在一起形成可執行文件。執行文件。4.1 概述概述在一個程序文件中可以包含若干個函數。無論在一個程序文件中可以包含若干個函數。無論把一個程序劃分為多少個程序模塊,把一個程序劃分為多少個程序模塊,只能有一個只能有一個main函數函數。程序總是從程序總是從main函數開始執行的。函數開始執行的。在在程序運行過程中,由主函數調用其他

4、函數,其他函程序運行過程中,由主函數調用其他函數,其他函數也可以互相調用。在數也可以互相調用。在C語言中沒有類和對象,在語言中沒有類和對象,在程序模塊中直接定義函數。可以認為,一個程序模塊中直接定義函數。可以認為,一個C程序程序是由若干個函數組成的,是由若干個函數組成的,C語言被認為是面向函數語言被認為是面向函數的語言。的語言。C+面向過程的程序設計沿用了面向過程的程序設計沿用了C語言使語言使用函數的方法。用函數的方法。在在C+面向對象的程序設計中,主函數以外的面向對象的程序設計中,主函數以外的函數大多是被封裝在類中的。主函數或其他函數可函數大多是被封裝在類中的。主函數或其他函數可以通過類對象

5、調用類中的函數。以通過類對象調用類中的函數。無論是無論是C還是還是C+,程序中的各項操作基本上都是由函數來實現的程序中的各項操作基本上都是由函數來實現的,程,程序編寫者要根據需要編寫一個個函數,每個函數用序編寫者要根據需要編寫一個個函數,每個函數用來實現某一功能。來實現某一功能。“函數函數”這個名詞是從英文這個名詞是從英文function翻譯過來的,翻譯過來的,其實其實function的原意是的原意是“功能功能”。顧名思義,一個。顧名思義,一個函數就是一個功能。函數就是一個功能。在實際應用的程序中,主函數寫得很簡單,它的作在實際應用的程序中,主函數寫得很簡單,它的作用就是調用各個函數,程序各部

6、分的功能全部都是用就是調用各個函數,程序各部分的功能全部都是由各函數實現的。主函數相當于總調度,調動各函由各函數實現的。主函數相當于總調度,調動各函數依次實現各項功能。數依次實現各項功能。開發商和軟件開發人員將一些常用的功能模塊編寫開發商和軟件開發人員將一些常用的功能模塊編寫成函數,放在成函數,放在函數庫函數庫中供公共選用。程序開發人員中供公共選用。程序開發人員要善于利用庫函數,以減少重復編寫程序段的工作要善于利用庫函數,以減少重復編寫程序段的工作量。量。圖圖4.是一個程序中函數調用的示意圖。是一個程序中函數調用的示意圖。圖圖4.例例41 在主函數中調用其他函數。在主函數中調用其他函數。#in

7、clude using namespace std;void printstar(void) /定義定義printstar函數函數 cout* endl; /輸出輸出30個個“*”void print_message(void) /定義定義print_message函數函數 cout Welcome to C+!y?x:y; /將將x和和y中的大者的值賦給整型變量中的大者的值賦給整型變量zreturn (z); /將將z的值作為函數值返回調用點的值作為函數值返回調用點C+要求在定義函數時必須指定函數的類型。要求在定義函數時必須指定函數的類型。4.2.2 定義有參函數的一般形式定義有參函數的一般

8、形式在調用函數時,大多數情況下,函數是帶參數的。在調用函數時,大多數情況下,函數是帶參數的。主調函數和被調用函數之間有數據傳遞關系。前面主調函數和被調用函數之間有數據傳遞關系。前面已提到:在定義函數時函數名后面括號中的變量名已提到:在定義函數時函數名后面括號中的變量名稱為形式參數(稱為形式參數(formal parameter,簡稱簡稱形參形參),),在主調函數中調用一個函數時,函數名后面括號中在主調函數中調用一個函數時,函數名后面括號中的參數的參數(可以是一個表達式可以是一個表達式)稱為實際參數(稱為實際參數(actual parameter,簡稱簡稱實參實參)。)。4.3 函數參數和函數的

9、值函數參數和函數的值 4.3.1 形式參數和實際參數形式參數和實際參數int max(int x,int y) int z; if(xy) z=x; else z=y; return(z); int main( ) int a,b,m; cinab; m=max(a,b); f(x,y) = x + yf(1,2) 1+2定義形式參數調用實際參數例例4.2 調用函數時的數據傳遞。調用函數時的數據傳遞。#include using namespace std;int max(int x,int y) /定義有參函數定義有參函數maxint z; z=xy?x:y; return(z); int

10、main( )int a,b,c; coutab; c=max(a,b); /調用調用max函數,給定實參為函數,給定實參為a,b。函數值賦給函數值賦給c coutmax=cy?x:y; return(z); int main( )int a,b,c; coutab; c=max(a,b); coutmax=cendl; return 0; 3x返回地址調用者狀態4c4b3a返回地址OS狀態4ymain( )max( )4z注意箭頭的方向注意箭頭的方向運行情況如下:運行情況如下:please enter two integer numbers:2 3 max=3圖圖4.2有關形參與實參的說明:

11、有關形參與實參的說明:(1) 在定義函數時指定的形參,在未出現函數調用在定義函數時指定的形參,在未出現函數調用時,它們并不占內存中的存儲單元,因此稱它們是時,它們并不占內存中的存儲單元,因此稱它們是形式參數或虛擬參數形式參數或虛擬參數,表示它們并不是實際存在的,表示它們并不是實際存在的數據,只有在發生函數調用時,函數數據,只有在發生函數調用時,函數max中的形參中的形參才被分配內存單元,以便接收從實參傳來的數據。才被分配內存單元,以便接收從實參傳來的數據。在調用結束后,形參所占的內存單元也被釋放。在調用結束后,形參所占的內存單元也被釋放。(2) 實參可以是常量、變量或表達式,如實參可以是常量、

12、變量或表達式,如max(3, a+b);但要求但要求a和和b有確定的值。以便在調用函數時有確定的值。以便在調用函數時將實參的值賦給形參。將實參的值賦給形參。(3) 在定義函數時,必須在函數首部指定形參的類在定義函數時,必須在函數首部指定形參的類型(見例型(見例4.2程序第程序第3行)。行)。(4) 實參與形參的實參與形參的類型應相同或賦值兼容類型應相同或賦值兼容。例。例4.2中中實參和形參都是整型,這是合法的、正確的。如果實參和形參都是整型,這是合法的、正確的。如果實參為整型而形參為實型,或者相反,則按不同類實參為整型而形參為實型,或者相反,則按不同類型數值的賦值規則進行轉換。例如實參型數值的

13、賦值規則進行轉換。例如實參a的值為的值為3.5,而形參而形參x為整型,則將為整型,則將3.5轉換成整數轉換成整數3,然后送到,然后送到形參形參b。字符型與整型可以互相通用。字符型與整型可以互相通用。(5) 實參變量對形參變量的數據傳遞是實參變量對形參變量的數據傳遞是“值傳遞值傳遞”,即單向傳遞,即單向傳遞,只能由實參傳給形參,而不能由形參只能由實參傳給形參,而不能由形參傳回來給實參傳回來給實參。在調用函數時,編譯系統臨時給形。在調用函數時,編譯系統臨時給形參分配存儲單元。請注意:參分配存儲單元。請注意: 實參單元與形參單元實參單元與形參單元是不同的單元。圖是不同的單元。圖4.3表示將實參和的值

14、表示將實參和的值2和和3傳遞給對應的形參和。傳遞給對應的形參和。 圖圖4.3 圖圖4.4調用結束后,形參單元被釋放,實參單元仍保留并調用結束后,形參單元被釋放,實參單元仍保留并維持原值。因此,在執行一個被調用函數時,形參維持原值。因此,在執行一個被調用函數時,形參的值如果發生改變,并不會改變主調函數中實參的的值如果發生改變,并不會改變主調函數中實參的值。例如,若在執行值。例如,若在執行max函數過程中形參和的函數過程中形參和的值變為值變為10和和15,調用結束后,實參和仍為,調用結束后,實參和仍為2和和3,見圖見圖4.4。函數調用時內存空間分配情況void funcA(int,int);voi

15、d funcB(int);void main( )int a=6, b=12;funcA(a,b);void funcA(int aa, int bb)int n=5;funcB(n);void funcB(int s)int x;函數調用返回main()時內存空間分配情況(1) 函數的返回值是通過函數中的函數的返回值是通過函數中的return語句獲得語句獲得的。的。return語句將被調用函數中的一個確定值帶回語句將被調用函數中的一個確定值帶回主調函數中去。主調函數中去。return語句后面的括號可以要,也可以不要。語句后面的括號可以要,也可以不要。return后面可以是一個表達式。后面可以

16、是一個表達式。(2) 函數值的類型。既然函數有返回值,這個值當函數值的類型。既然函數有返回值,這個值當然應屬于某一個確定的類型,應當在定義函數時指然應屬于某一個確定的類型,應當在定義函數時指定函數值的類型。定函數值的類型。(3) 如果函數值的類型和如果函數值的類型和return語句中表達式的值語句中表達式的值不一致,則以函數類型為準,即函數類型決定返回不一致,則以函數類型為準,即函數類型決定返回值的類型。對數值型數據,可以自動進行類型轉換。值的類型。對數值型數據,可以自動進行類型轉換。4.3.2 函數的返回值函數的返回值#include using namespace std;int max(

17、int x,int y) /定義有參函數定義有參函數maxint z; z=xy?x:y; return(z); int main( )int a,b,c; coutab; c=max(a,b); /調用調用max函數,給定實參為函數,給定實參為a,b。函數值賦給函數值賦給c coutmax=cy?x:y; return(z); int main( )int a,b,c; coutab; c=max(a,b); coutmax=cendl; return 0; 3x返回地址調用者狀態4c4b3a返回地址OS狀態4ymain( )max( )4z注意箭頭的方向注意箭頭的方向按函數在語句中的作用來

18、分,可以有以下按函數在語句中的作用來分,可以有以下3種函數種函數調用方式:調用方式:. 函數語句函數語句把函數調用單獨作為一個語句,并不要求函數帶回把函數調用單獨作為一個語句,并不要求函數帶回一個值,只是要求函數完成一定的操作。如例一個值,只是要求函數完成一定的操作。如例4.1中的中的printstar( );2. 函數表達式函數表達式函數出現在一個表達式中,這時要求函數帶回一個函數出現在一個表達式中,這時要求函數帶回一個確定的值以參加表達式的運算。如確定的值以參加表達式的運算。如c=2*max(a,b);4.4.2 函數調用的方式函數調用的方式3. 函數參數函數參數函數調用作為一個函數的實參

19、。如函數調用作為一個函數的實參。如m=max(a, max(b,c) ); /max(b,c)是函數調用,其值作為外層是函數調用,其值作為外層max函數調用的函數調用的 /一個實參一個實參4.4.2 函數調用的方式函數調用的方式在一個函數中調用另一個函數(即被調用函數)需在一個函數中調用另一個函數(即被調用函數)需要具備哪些條件呢?要具備哪些條件呢?(1) 首先被調用的函數必須是已經存在的函數。首先被調用的函數必須是已經存在的函數。(2) 如果使用庫函數,一般還應該在本文件開頭用如果使用庫函數,一般還應該在本文件開頭用include命令將有關頭文件命令將有關頭文件“包含包含”到本文件中來。到本

20、文件中來。4.4.3 對被調用函數的聲明和函數原型對被調用函數的聲明和函數原型(3) 如果使用用戶自己定義的函數,而該函數與調如果使用用戶自己定義的函數,而該函數與調用它的函數(即主調函數)在同一個程序單位中用它的函數(即主調函數)在同一個程序單位中,且位置在主調函數之后,則必須在調用此函數之前且位置在主調函數之后,則必須在調用此函數之前對被調用的函數作聲明對被調用的函數作聲明。所謂函數聲明所謂函數聲明(declare),就是在函數尚在未定義的就是在函數尚在未定義的情況下,事先將該函數的有關信息通知編譯系統,情況下,事先將該函數的有關信息通知編譯系統,以便使編譯能正常進行。以便使編譯能正常進行

21、。4.4.3 對被調用函數的聲明和函數原型對被調用函數的聲明和函數原型總結:總結:先定義后使用;先定義后使用;若要先使用后定義,則在使用前先聲明若要先使用后定義,則在使用前先聲明。4.4.3 對被調用函數的聲明和函數原型對被調用函數的聲明和函數原型例例4.3 對被調用的函數作聲明。對被調用的函數作聲明。#include using namespace std;float add(float x,float y) /定義定義add函數函數float z; z=x+y; return (z); int main( ) float a,b,c;coutab; c=add(a,b); coutsum=

22、cendl; return 0; 例例4.3 對被調用的函數作聲明。對被調用的函數作聲明。#include using namespace std;int main( )float add(float x,float y); /對對add函數函數作聲明作聲明 float a,b,c;coutab; c=add(a,b); coutsum=cy?x:y; return(z); int main( )int a,b,c; coutab; c=max(a,b); coutmax=cendl; return 0; 3x返回地址調用者狀態4c4b3a返回地址OS狀態4ymain( )max( )4z注意

23、箭頭的方向注意箭頭的方向例例4.3 對被調用的函數作聲明。對被調用的函數作聲明。#include using namespace std;int main( )float add(float x,float y); /對對add函數作聲明函數作聲明 float a,b,c;coutab; c=add(a,b); coutsum=cendl; return 0; float add(float x,float y) /定義定義add函數函數float z; z=x+y; return (z); C+提供一種提高效率的方法,即在編譯時將所調提供一種提高效率的方法,即在編譯時將所調用函數的代碼直接嵌

24、入到主調函數中,而不是將流用函數的代碼直接嵌入到主調函數中,而不是將流程轉出去。這種嵌入到主調函數中的函數稱為程轉出去。這種嵌入到主調函數中的函數稱為內置內置函數函數(inline function),又稱又稱內嵌函數內嵌函數。在有些書中。在有些書中把它譯成把它譯成內聯函數內聯函數。指定內置函數的方法很簡單,只需在函數首行的左指定內置函數的方法很簡單,只需在函數首行的左端加一個關鍵字端加一個關鍵字inline即可。即可。例例4.4 函數指定為內置函數。函數指定為內置函數。#include using namespace std;inline int max(int,int, int); /聲明

25、函數,注意左端有聲明函數,注意左端有inlineint main( )int i=10,j=20,k=30,m; m=max(i,j,k); coutmax=ma) a=b; /求求a,b,c中的最大者中的最大者 if(ca) a=c; return a; #include using namespace std;inline int max(int,int, int); /聲明函數,注意左端有聲明函數,注意左端有inlineint main( )int i=10,j=20,k=30, m;if (ji) i=j;/ m=max(i,j,k);if(ki) i=k;m=i; coutmax=m

26、a) a=b; /求求a,b,c中的最大者中的最大者 if(ca) a=c; return a;由于在定義函數時指定它為內置函數,因此編譯系由于在定義函數時指定它為內置函數,因此編譯系統在遇到函數調用統在遇到函數調用“max(i,j,k)”時,就用時,就用max函數函數體的代碼體的代碼代替代替“max(i,j,k)”,同時將實參代替形參同時將實參代替形參。這樣,程序第這樣,程序第6行行 “m=max(i,j,k);”就被置換成就被置換成if (ji) i=j;if(ki) i=k;m=i;一般只將規模很小一般只將規模很小(一般為一般為5個語句以下個語句以下)而使用頻而使用頻繁的函數繁的函數(如

27、定時采集數據的函數如定時采集數據的函數)聲明為內置函數。聲明為內置函數。內置函數中內置函數中不能包括復雜的控制語句不能包括復雜的控制語句,如循環語句,如循環語句和和switch語句。語句。說明說明: 對函數作對函數作inline聲明,只是程序設計者對編聲明,只是程序設計者對編譯系統提出的一個建議,也就是說它是建議性的,譯系統提出的一個建議,也就是說它是建議性的,而不是指令性的。并非一經指定為而不是指令性的。并非一經指定為inline,編譯系編譯系統就必須這樣做。編譯系統會根據具體情況決定是統就必須這樣做。編譯系統會根據具體情況決定是否這樣做。否這樣做。在編程時,有時我們要實現的是在編程時,有時

28、我們要實現的是同一類的功能同一類的功能,只,只是有些細節不同。例如希望從是有些細節不同。例如希望從3個數中找出其中的個數中找出其中的最大者,而每次求最大數時數據的類型不同,可能最大者,而每次求最大數時數據的類型不同,可能是是3個個整數整數、3個個雙精度數雙精度數或或3個個長整數長整數。程序設計。程序設計者往往會分別設計出者往往會分別設計出3個不同名的函數,其函數原個不同名的函數,其函數原型為:型為:int max1(int a,int b, int c); /求求3個整數中的最大者個整數中的最大者double max2(double a,double b,double c); /求求3個雙精度

29、數中最大者個雙精度數中最大者long max3(long a,long b,long c); /求求3個長整數中的最大者個長整數中的最大者C+允許用同一函數名定義多個函數,這些函數的允許用同一函數名定義多個函數,這些函數的參數個數和參數類型不同。這就是函數的重載參數個數和參數類型不同。這就是函數的重載(function overloading)。即對一個函數名重新賦予即對一個函數名重新賦予它新的含義,使一個它新的含義,使一個函數名可以多用函數名可以多用。*4.6 函數的重載函數的重載對上面求最大數的問題可以編寫如下的對上面求最大數的問題可以編寫如下的C+程序。程序。例例4.5 求求3個數中最大

30、的數(分別考慮整數、雙精度個數中最大的數(分別考慮整數、雙精度數、長整數的情況)。數、長整數的情況)。#include using namespace std;int main( )int max(int a,int b,int c); /函數聲明函數聲明double max(double a,double b,double c); /函數聲明函數聲明long max(long a,long b,long c); /函數聲明函數聲明 int i1,i2,i3,i; cini1i2i3; /輸入輸入3個整數個整數 i=max(i1,i2,i3); /求求3個整數中的最大者個整數中的最大者 cou

31、ti_max=id1d2d3; /輸入輸入3個雙精度數個雙精度數 d=max(d1,d2,d3); /求求3個雙精度數中的最大者個雙精度數中的最大者 coutd_max=dg1g2g3; /輸入輸入3個長整數個長整數 g=max(g1,g2,g3); /求求3個長整數中的最大者個長整數中的最大者 coutg_max=ga) a=b; if(ca) a=c; return a; double max(double a,double b,double c) /定義求定義求3個雙精度數中的最大者的函數個雙精度數中的最大者的函數if(ba) a=b; if(ca) a=c; return a; lon

32、g max(long a,long b,long c) /定義求定義求3個長整數中的最大者的函數個長整數中的最大者的函數if(ba) a=b; if(ca) a=c; return a; 運行情況如下:運行情況如下:185 -76 567 (輸入輸入3個整數個整數)56.87 90.23 -3214.78 (輸入輸入3個實數個實數)67854 -912456 673456 (輸入輸入3個長整數個長整數)i_max=567 (輸出輸出3個整數的最大值)個整數的最大值)d_max=90.23 (輸出輸出3個雙精度數的最大值)個雙精度數的最大值)g_max=673456 (輸出輸出3個長整數的最大值

33、)個長整數的最大值)上例上例3個個max函數的函數體是相同的,其實重載函函數的函數體是相同的,其實重載函數數并不要求函數體相同并不要求函數體相同。重載函數除了允許參數類。重載函數除了允許參數類型不同以外,還允許型不同以外,還允許參數的個數不同參數的個數不同。例例4.6 編寫一個程序,用來求兩個整數或編寫一個程序,用來求兩個整數或3個整數中個整數中的最大數。如果輸入兩個整數,程序就輸出這兩個的最大數。如果輸入兩個整數,程序就輸出這兩個整數中的最大數,如果輸入整數中的最大數,如果輸入3個整數,程序就輸出個整數,程序就輸出這這3個整數中的最大數。個整數中的最大數。#include using nam

34、espace std;int main( )int max(int a,int b,int c); /函數聲明函數聲明 int max(int a,int b); /函數聲明函數聲明 int a=8,b=-12,c=27; coutmax(a,b,c)=max(a,b,c)endl; /輸出輸出3個整數中的最大者個整數中的最大者 coutmax(a,b)=max(a,b)a) a=b; if(ca) a=c; return a;int max(int a,int b) /此此max函數的作用是求兩個整數中的最大者函數的作用是求兩個整數中的最大者if(ab) return a;else retu

35、rn b;運行情況如下:運行情況如下:max(a,b,c)=27max(a,b)=8兩次調用兩次調用max函數的參數個數不同,系統就根據參函數的參數個數不同,系統就根據參數的個數找到與之匹配的函數并調用它。數的個數找到與之匹配的函數并調用它。參數的個數和類型可以都不同。但不能只有函數的參數的個數和類型可以都不同。但不能只有函數的類型不同而參數的個數和類型相同。例如:類型不同而參數的個數和類型相同。例如:int f(int); /函數返回值為整型函數返回值為整型long f(int); /函數返回值為長整型函數返回值為長整型void f(int); /函數無返回值函數無返回值在函數調用時都是同一

36、形式,如在函數調用時都是同一形式,如“f(10)”。編譯系編譯系統無法判別應該調用哪一個函數。統無法判別應該調用哪一個函數。在使用重載函數時,同名函數的功能應當相同或相在使用重載函數時,同名函數的功能應當相同或相近,不要用同一函數名去實現完全不相干的功能,近,不要用同一函數名去實現完全不相干的功能,雖然程序也能運行,但可讀性不好,使人莫名其妙。雖然程序也能運行,但可讀性不好,使人莫名其妙。注意:注意:重載函數的參數個數、參數類型或參數順序重載函數的參數個數、參數類型或參數順序3者中必須至少有者中必須至少有一種不同,一種不同,函數返回值類型可以相同也可以不同。函數返回值類型可以相同也可以不同。

37、i = max(i1,i2,i3); /求求3個整數中的最大者個整數中的最大者d = max(d1,d2,d3); /求求3個雙精度數中的最大者個雙精度數中的最大者g = max(g1,g2,g3); /求求3個長整數中的最大者個長整數中的最大者max(a,b,c);max(a,b);int max(int a,int b,int c) /定義求定義求3個整數中的最大者的函數個整數中的最大者的函數if(ba) a=b; if(ca) a=c; return a; double max(double a,double b,double c) /定義求定義求3個雙精度數中的最大者的函數個雙精度數中

38、的最大者的函數if(ba) a=b; if(ca) a=c; return a; long max(long a,long b,long c) /定義求定義求3個長整數中的最大者的函數個長整數中的最大者的函數if(ba) a=b; if(ca) a=c; return a; int max(int a,int b,int c) /此此max函數的作用是求函數的作用是求3個整數中的最大者個整數中的最大者if(ba) a=b; if(ca) a=c; return a;int max(int a,int b) /此此max函數的作用是求兩個整數中的最大者函數的作用是求兩個整數中的最大者if(ab)

39、 return a;else return b;C+提供了函數模板提供了函數模板(function template)。所謂函數所謂函數模板,實際上是建立一個模板,實際上是建立一個通用函數通用函數,其函數類型和,其函數類型和形參類型不具體指定,用一個虛擬的類型來代表。形參類型不具體指定,用一個虛擬的類型來代表。這個通用函數就稱為函數模板。這個通用函數就稱為函數模板。凡是函數體相同的凡是函數體相同的函數都可以用這個模板來代替函數都可以用這個模板來代替,不必定義多個函數,不必定義多個函數,只需在模板中定義一次即可。在調用函數時系統會只需在模板中定義一次即可。在調用函數時系統會根據實參的類型來取代模

40、板中的虛擬類型,從而實根據實參的類型來取代模板中的虛擬類型,從而實現了不同函數的功能。看下面的例子就清楚了。現了不同函數的功能。看下面的例子就清楚了。例例4.7 將例將例4.6程序改為通過函數模板來實現。程序改為通過函數模板來實現。*4.7 函數模板函數模板#include using namespace std;template /模板聲明,其中模板聲明,其中T為為類型參數類型參數T max(T a,T b,T c) /定義一個通用函數,用定義一個通用函數,用T作虛擬的類型名作虛擬的類型名if(ba) a=b; if(ca) a=c; return a;int main( )int i1=1

41、85, i2=-76, i3=567,i; double d1=56.87, d2=90.23, d3=-3214.78,d; long g1=67854, g2=-912456, g3=673456,g; i= max(i1,i2,i3); /調用模板函數,此時調用模板函數,此時T被被int取代取代 d=max(d1,d2,d3); /調用模板函數,此時調用模板函數,此時T被被double取代取代 g=max(g1,g2,g3); /調用模板函數,此時調用模板函數,此時T被被long取代取代 couti_max=iendl; coutf_max=fendl; coutg_max=gendl;

42、 return 0;運行結果與例運行結果與例4.5相同。為了節省篇幅,數據不用相同。為了節省篇幅,數據不用cin語句輸入,而在變量定義時初始化。語句輸入,而在變量定義時初始化。程序第程序第38行是定義模板。定義函數模板的一般形行是定義模板。定義函數模板的一般形式為式為 template 或或 template 通用函數定義通用函數定義 通用函數定義通用函數定義在建立函數模板時,只要將例在建立函數模板時,只要將例4.5程序中定義的第程序中定義的第一個函數首部的一個函數首部的int改為改為T即可。即用即可。即用虛擬的類型名虛擬的類型名T代替具體的數據類型。在對程序進行編譯時,遇代替具體的數據類型。

43、在對程序進行編譯時,遇到第到第13行調用函數行調用函數max(i1,i2,i3),編譯系統會將函編譯系統會將函數名數名max與模板與模板max相匹配,將實參的類型取代了相匹配,將實參的類型取代了函數模板中的虛擬類型函數模板中的虛擬類型T。此時相當于已定義了一此時相當于已定義了一個函數:個函數:int max(int a,int b,int c)if(ba) a=b; if(ca) a=c; return a;然后調用它。后面兩行然后調用它。后面兩行(14,15行行)的情況類似。的情況類似。類型參數可以不只一個,可以根據需要確定個數。類型參數可以不只一個,可以根據需要確定個數。如如templat

44、e 可以看到,用函數模板比函數重載更方便,程序更可以看到,用函數模板比函數重載更方便,程序更簡潔。簡潔。但應注意它只適用于函數的參數個數相同而但應注意它只適用于函數的參數個數相同而類型不同,且函數體相同的情況,類型不同,且函數體相同的情況,如果參數的個數如果參數的個數不同,則不能用函數模板。不同,則不能用函數模板。一般情況下,在函數調用時形參從實參那里取得值,一般情況下,在函數調用時形參從實參那里取得值,因此實參的個數應與形參相同。有時多次調用同一因此實參的個數應與形參相同。有時多次調用同一函數時用同樣的實參,函數時用同樣的實參,C+提供簡單的處理辦法,提供簡單的處理辦法,給形參一個默認值,這

45、樣形參就不必一定要從實參給形參一個默認值,這樣形參就不必一定要從實參取值了。取值了。*4.8 有默認參數的函數有默認參數的函數如有一函數聲明如有一函數聲明float area(float r=6.5);指定指定r的默認值為的默認值為6.5,如果在調用此函數時,確認,如果在調用此函數時,確認r的值為的值為6.5,則可以不必給出實參的值,如,則可以不必給出實參的值,如area( ); /相當于相當于area(6.5);如果不想使形參取此默認值,則通過實參另行給出。如果不想使形參取此默認值,則通過實參另行給出。如如area(7.5); /形參得到的值為形參得到的值為7.5,而不是,而不是6.5這種方

46、法比較靈活,可以簡化編程,提高運行效率。這種方法比較靈活,可以簡化編程,提高運行效率。*4.8 有默認參數的函數有默認參數的函數如果有多個形參,可以使每個形參有一個默認值,也如果有多個形參,可以使每個形參有一個默認值,也可以只對一部分形參指定默認值,另一部分形參不指可以只對一部分形參指定默認值,另一部分形參不指定默認值。定默認值。如有一個求圓柱體體積的函數,形參如有一個求圓柱體體積的函數,形參h代表圓柱體的高,代表圓柱體的高,r為圓柱體半徑。函數原型如下:為圓柱體半徑。函數原型如下:float volume(float h, float r=12.5); /只對形參只對形參r指定默認值指定默認

47、值12.5函數調用可以采用以下形式:函數調用可以采用以下形式: volume(45.6); /相當于相當于volume(45.6,12.5)volume(34.2,10.4) /h的值為的值為34.2,r的值為的值為10.4實參與形參的結合是從左至右順序進行的實參與形參的結合是從左至右順序進行的。因此指定默認。因此指定默認值的參數必須放在形參表列中的最右端,否則出錯。例如:值的參數必須放在形參表列中的最右端,否則出錯。例如:void f1(float a,int b=0,int c,char d=a); /不正確不正確, f2(3.5, 5)?void f2(float a,int c,int

48、 b=0, char d=a); /正確正確如果調用上面的如果調用上面的f2函數,可以采取下面的形式:函數,可以采取下面的形式: f2(3.5, 5, 3, x) /形參的值全部從實參得到形參的值全部從實參得到f2(3.5, 5, 3) /最后一個形參的值取默認值最后一個形參的值取默認值af2(3.5, 5) /最后兩個形參的值取默認值,最后兩個形參的值取默認值,b=0,d=a可以看到,在調用有默認參數的函數時,實參的個可以看到,在調用有默認參數的函數時,實參的個數可以與形參的個數不同,實參未給定的,從形參數可以與形參的個數不同,實參未給定的,從形參的默認值得到值。利用這一特性,可以使函數的使

49、的默認值得到值。利用這一特性,可以使函數的使用更加靈活。例如例用更加靈活。例如例4.7求求2個數或個數或3個數中的最大個數中的最大數。也可以不用重載函數,而改用帶有默認參數的數。也可以不用重載函數,而改用帶有默認參數的函數。函數。例例4.8 求求2個或個或3個個正正整數中的最大數,用帶有默認整數中的最大數,用帶有默認參數的函數實現。參數的函數實現。int main( )int max(int a, int b, int c=0); /函數聲明函數聲明,形參形參c有默認值有默認值int a,b,c; cinabc; coutmax(a,b,c)=max(a,b,c)endl; /輸出輸出3個數中

50、的最大者個數中的最大者 coutmax(a,b)=max(a,b)a) a=b; if(ca) a=c; return a; 運行情況如下:運行情況如下:14 -56 135 max(a,b,c)=135max(a,b)=14在使用帶有默認參數的函數時有兩點要注意:在使用帶有默認參數的函數時有兩點要注意:(1) 如果函數的定義在函數調用之前,則應在函數如果函數的定義在函數調用之前,則應在函數定義中給出默認值。如果函數的定義在函數調用之定義中給出默認值。如果函數的定義在函數調用之后,則在函數調用之前需要有函數聲明,此時必須后,則在函數調用之前需要有函數聲明,此時必須在函數聲明中給出默認值,在函數

51、定義時可以不給在函數聲明中給出默認值,在函數定義時可以不給出默認值出默認值(如例如例4.8)。(2) 一個函數不能既作為重載函數,又作為有默認一個函數不能既作為重載函數,又作為有默認參數的函數。因為當調用函數時如果少寫一個參數,參數的函數。因為當調用函數時如果少寫一個參數,系統無法判定是利用重載函數還是利用默認參數的系統無法判定是利用重載函數還是利用默認參數的函數,出現二義性,系統無法執行。函數,出現二義性,系統無法執行。C+不允許對函數作嵌套定義,也就是說在一個函不允許對函數作嵌套定義,也就是說在一個函數中不能完整地包含另一個函數。在一個程序中每數中不能完整地包含另一個函數。在一個程序中每一

52、個函數的定義都是互相平行和獨立的。一個函數的定義都是互相平行和獨立的。雖然雖然C+不能嵌套定義函數,但可以嵌套調用函數,不能嵌套定義函數,但可以嵌套調用函數,也就是說,在調用一個函數的過程中,又調用另一也就是說,在調用一個函數的過程中,又調用另一個函數。見圖個函數。見圖4.6。 4.9 函數的嵌套調用函數的嵌套調用 圖圖4.6例例4.9 用弦截法求方程用弦截法求方程f(x)=x3-5x2+16x-80=0的根。的根。這是一個數值求解問題,需要先分析用弦截法求根這是一個數值求解問題,需要先分析用弦截法求根的的算法算法。根據數學知識,可以列出以下的解題步驟:根據數學知識,可以列出以下的解題步驟:

53、(1) 取兩個不同點取兩個不同點x1,x2,如果如果f(x1)和和f(x2)符號符號相反,則相反,則(x1,x2)區間內必有一個根。如果區間內必有一個根。如果f(x1)與與f(x2)同符號,則應改變同符號,則應改變x1,x2,直到直到f(x1),),f(x2)異異號為止。注意號為止。注意x1、x2的值不應差太大的值不應差太大,以保證以保證(x1,x2)區間內只有一個根。區間內只有一個根。(2) 連接連接(x1, f(x1))和和(x2, f(x2))兩點兩點,此線此線(即弦即弦)交交x軸于軸于x,見圖見圖4.7。x1x1 xf(x1)f(x)f(x)=x3-5x2+16x-80=0 的根x1x

54、1 xf(x1)f(x)根x點坐標可由下式求出:點坐標可由下式求出:再由再由x求出求出f(x)。(3) 若若f(x)與與f(x1)同符號同符號,則根必在則根必在(x, x2)區間內區間內,此此時將時將x作為新的作為新的x1。如果如果f(x)與與f(x2)同符號同符號,則表則表示根在示根在( x1,x)區間內區間內,將將x作為新的作為新的x2。(4) 重復步驟重復步驟 (2) 和和 (3), 直到直到 f(x)為止為止, 為為一個很小的正數一個很小的正數, 例如例如10-6。此時認為。此時認為 f(x)0,這時這時的的x即為即為f(x)=x3-5x2+16x-80=0的根的近似值的根的近似值。1

55、22121()()()()xf xxf xxf xf x這就是弦截法的算法,在程序中分別用以下幾個函這就是弦截法的算法,在程序中分別用以下幾個函數來實現以上有關部分功能:數來實現以上有關部分功能:(1) 用函數用函數f(x)代表代表x的函數:的函數:x3-5x2+16x-80。(2) 用函數用函數xpoint (x1,x2)來求來求(x1,f(x1)和和(x2,f(x2)的連的連線與線與x軸的交點軸的交點x的坐標。的坐標。(3) 用函數用函數root(x1,x2)來求來求(x1,x2)區間的那個實根。區間的那個實根。顯然顯然,執行執行root函數的過程中要用到函數的過程中要用到xpoint函數

56、函數,而執而執行行xpoint函數的過程中要用到函數的過程中要用到 f(x) 函數。函數。根據以上算法,可以編寫出下面的程序根據以上算法,可以編寫出下面的程序:#include #include #include using namespace std;double f(double); /函數聲明函數聲明 double xpoint(double, double); /函數聲明函數聲明double root(double, double); /函數聲明函數聲明int main( ) double x1,x2,f1,f2,x; do coutx1x2; f1=f(x1); f2=f(x2);

57、while( f1*f2 =0 ); x=root(x1,x2); coutsetiosflags(ios fixed)setprecision(7); /指定輸出指定輸出7位小數位小數 coutA root of equation is x0) y1=y; x1=x; elsex2=x; while(fabs(y)=0.00001); return x; x1x1 xf(x1)f(x)y1=yroot(double x1, double x2)的執行過程運行情況如下:運行情況如下:input x1,x2:2.5 6.7 A root of equation is 5.0000000對程序的說

58、明:對程序的說明:(1) 在定義函數時,函數名為在定義函數時,函數名為f,xpoint和和root的的3個個函數是互相獨立的,并不互相從屬。這函數是互相獨立的,并不互相從屬。這3個函數均個函數均定為雙精度型。定為雙精度型。(2) 3個函數的定義均出現在個函數的定義均出現在main函數之后,因此在函數之后,因此在main函數的前面對這函數的前面對這3個函數作聲明。個函數作聲明。(3) 程序從程序從main函數開始執行。函數的嵌套調用見函數開始執行。函數的嵌套調用見圖圖4.8。圖圖4.8(4) 在在root函數中要用到求絕對值的函數函數中要用到求絕對值的函數fabs,它是它是對雙精度數求絕對值的系

59、統函數。它屬于數學函數對雙精度數求絕對值的系統函數。它屬于數學函數庫,故在文件開頭用庫,故在文件開頭用#include 把有關的頭把有關的頭文件包含進來。文件包含進來。 在調用一個函數的過程中又出現直接或間接地調用在調用一個函數的過程中又出現直接或間接地調用該函數本身,稱為函數的該函數本身,稱為函數的遞歸遞歸(recursive)調用調用。例。例如:如:int f(int x)int y,z;z=f(y); /在調用函數在調用函數f的過程中,又要調用的過程中,又要調用f函數函數return (2*); 以上是直接調用本函數,見圖以上是直接調用本函數,見圖4.9。4.10 函數的遞歸調用函數的遞

60、歸調用 圖圖4.9 圖圖4.10圖圖4.10表示的是間接調用本函數。表示的是間接調用本函數。這兩種遞歸調用都是無終止的自身調用。程序中不這兩種遞歸調用都是無終止的自身調用。程序中不應出現這種無終止的遞歸調用,遞歸調用應是有限應出現這種無終止的遞歸調用,遞歸調用應是有限次數的、能終止的,這可以用次數的、能終止的,這可以用if語句來控制,只有語句來控制,只有在某一條件成立時才繼續執行遞歸調用,否則就不在某一條件成立時才繼續執行遞歸調用,否則就不再繼續。再繼續。包含遞歸調用的函數稱為遞歸函數。包含遞歸調用的函數稱為遞歸函數。void funcA(int,int);void funcB(int);vo

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論