第5章 C++函數(shù)與程序結構
本章要點:
1、掌握函數(shù)的概念、定義和調用方法。
2、理解C++函數(shù)參數(shù)傳遞的方法:值傳遞和引用傳遞。掌握函數(shù)參數(shù)值傳遞的3、過程,并能夠靈活運用。后面的章節(jié)中,將進一步學習引用傳遞。
4、理解內聯(lián)函數(shù)的概念、作用,會定義內聯(lián)函數(shù)。
5、理解函數(shù)重載的概念、作用,能夠熟練地定義和運用重載的函數(shù)。
6、理解遞歸的概念,并能運用遞歸的方法解決一些實際問題。
7、理解變量的作用域與生存期的概念,能夠理解全局變量、局部變量、靜態(tài)變量的概念和用法。
C++語言認為函數(shù)是一個能完成某一獨立功能的子程序,也就是程序模塊。 函數(shù)就是對復雜問題的一種“自頂向下,逐步求精”思想的體現(xiàn)。編程者可以將一個大而復雜的程序分解為若干個相對獨立而且功能單一的小塊程序(函數(shù))進行編寫,并通過在各個函數(shù)之間進行調用,來實現(xiàn)總體的功能。
5.1函數(shù)概述
使用函數(shù)的優(yōu)點:
(1)可讀性好;
(2)易于查錯和修改;
(3)便于分工編寫,分階段調試;
(4)各個函數(shù)之間接口清晰,便于相互間交換信息和使用;
(5)節(jié)省程序代碼和存儲空間;
(6)減少用戶總的工作量;
(7)成為實現(xiàn)結構程序設計思想的重要工具;
(8)擴充語言和計算機的原設計能力;
(9)便于驗證程序正確性。
設計C++程序的過程,實際上就是編寫函數(shù)的過程,至少也要編寫一個main()函數(shù)。執(zhí)行C++程序,也就是執(zhí)行相應的main()函數(shù)。即從main()函數(shù)的第一個左花括號“{”開始,依次執(zhí)行后面的語句,直到最后一個右花括號“}”為止。
如果在執(zhí)行過程中遇到其他的函數(shù),則調用其他函數(shù)。調用完后,返回到剛才調用函數(shù)的下一條語句繼續(xù)執(zhí)行。而其他函數(shù)也只有在執(zhí)行main()函數(shù)的過程中被調用時才會執(zhí)行。
函數(shù)可以被一個函數(shù)調用,也可以調用另一個函數(shù),它們之間可以存在著調用上的嵌套關系。但是,C++不允許函數(shù)的定義嵌套,即在函數(shù)定義中再定義一個函數(shù)是非法的。
C++函數(shù)是一個獨立完成某個功能的語句塊,函數(shù)與函數(shù)之間通過輸入和輸出來聯(lián)系。
在C++程序中調用函數(shù)之前,首先要對函數(shù)進行定義。如果調用此函數(shù)在前,函數(shù)定義在后,就會產生編譯錯誤。
為了使函數(shù)的調用不受函數(shù)定義位置的影響,可以在調用函數(shù)前進行函數(shù)的聲明。這樣,不管函數(shù)是在哪里定義的,只要在調用前進行函數(shù)的聲明,就可以保證函數(shù)調用的合法性。
函數(shù)定義的一般形式如下:
返回類型 函數(shù)名(參數(shù)表列)
{ 語句系列
return 合適類型數(shù)值
}
函數(shù)的定義包括以下幾個部分:
1. 函數(shù)名
2. 參數(shù)表列
3. 返回類型
4. 函數(shù)體
l 函數(shù)名: 一個符合C++語法要求的標識符,定義函數(shù)名與定義變量名的規(guī)則是一樣的,但應盡量避免用下劃線開頭,因為編譯器常常定義一些下劃線開頭的變量或函數(shù)。函數(shù)名應盡可能反映函數(shù)的功能,它常常由幾個單詞組成。如VC中的按下鼠標左鍵的響應函數(shù)為:OnLButtonDown,這樣就較好的反映了函數(shù)的功能。
l 參數(shù)表列:0個或多個變量,用于向函數(shù)傳送數(shù)值或從函數(shù)帶回數(shù)值,每一個參數(shù)都有自己的類型,它不同于變量定義,因為幾個變量可以定義在一起,例如quot;int i,j,k;"。如果參數(shù)表列中參數(shù)個數(shù)為0,我們稱之為無參函數(shù),無參函數(shù)可以定義為:
"返回類型 函數(shù)名( ){…}"或"返回類型 函數(shù)名(void){…}"
l 返回類型:指定函數(shù)用return返回的函數(shù)值的類型,如果函數(shù)沒有返回值,返回類型應為void。
l 函數(shù)體:花括號中的語句稱為函數(shù)體,一個函數(shù)的功能,通過函數(shù)體中的語句來完成。
例如: 函數(shù)dec求兩個數(shù)的差值。
int dec(int x,int y)
{ return(x-y); }
例如: 函數(shù)out用于輸出兩個數(shù)的差值以及和值。
void out(int x,int y) //用void表示無返回值
{ cout<<x-y;
cout<<x+y;
}
例如:
int max(int a,int b)
{ intt;
if(a>b) t=a;
else t=b;
return t; }
5.2 函數(shù)的定義與聲明
在C++程序中調用函數(shù)之前,首先要對函數(shù)進行定義。如果調用此函數(shù)在前,函數(shù)定義在后,就會產生編譯錯誤。
為了使函數(shù)的調用不受函數(shù)定義位置的影響,可以在調用函數(shù)前進行函數(shù)的聲明。這樣,不管函數(shù)是在哪里定義的,只要在調用前進行函數(shù)的聲明,就可以保證函數(shù)調用的合法性。
C++中的每一個函數(shù)都是從四個方面來進行定義:類型、函數(shù)名、形式參數(shù)表、函數(shù)體。
定義一個函數(shù)的語法格式為:
類型 函數(shù)名(形式參數(shù)表)
{
函數(shù)體;
}
例如:
int max(int a,int b)
{
int t;
if(a>b) t=a;
else t=b;
return t;
}
類型就是該函數(shù)的類型,也就是該函數(shù)的返回值的類型,此類型可以是C++中除函數(shù)、數(shù)組類型之外的任何一個合法的數(shù)據(jù)類型,包括普通類型、指針類型和引用類型等。
函數(shù)的返回值通常指明了該函數(shù)處理的結果,由函數(shù)體中的return語句給出。一個函數(shù)可以有返回值,也可以無返回值(稱為無返回值函數(shù)或無類型函數(shù))。此時需要使用保留字void作為類型名,而且函數(shù)體中也不需要再寫return語句,或者return的后面什么也沒有。
每個函數(shù)都有類型,如果在函數(shù)定義時沒有明確指定類型,則默認類型為int。
函數(shù)名是一個有效的C++標識符,遵循一般的命名規(guī)則。在函數(shù)名后面必須跟一對小括號“()”,用來將函數(shù)名與變量名或其他用戶自定義的標識符區(qū)分開來。在小括號中可以沒有任何信息,也可以包含形式參數(shù)表。C++程序通過使用這個函數(shù)名和實參表可以調用該函數(shù)。
主函數(shù)的名稱規(guī)定取編譯器默認的名稱main()。
形式參數(shù)表又稱參數(shù)表,寫在函數(shù)名后面的一對圓括號內。它可包含任意多個(含0個,即沒有)參數(shù)說明項,當多于一個時其前后兩個參數(shù)說明項之間必須用逗號分開。
每個參數(shù)說明項由一種已定義的數(shù)據(jù)類型和一個變量標識符組成,該變量標識符稱為該函數(shù)的形式參數(shù),簡稱形參,形參前面給出的數(shù)據(jù)類型稱為該形參的類型。每個形參的類型可以為任一種數(shù)據(jù)類型,包括普通類型、指針類型、數(shù)組類型、引用類型等。
一個函數(shù)定義中的<參數(shù)表>可以被省略,表明該函數(shù)為無參函數(shù),若<參數(shù)表>用void取代,則也表明是無參函數(shù),若<參數(shù)表>不為空,同時又不是保留字void,則稱為帶參函數(shù)。
<函數(shù)體>是一條復合語句,它以左花括號開始,到右花括號結束,中間為一條或若干條C++語句,用于實現(xiàn)函數(shù)執(zhí)行的功能。
注意:在一個函數(shù)體內允許有一個或多個return語句,一旦執(zhí)行到其中某一個return語句時,return后面的語句就不再執(zhí)行,直接返回調用位置繼續(xù)向下執(zhí)行。
函數(shù)形參也可以在函數(shù)體外說明。如下例:
func1(int a, int b)
{
…
}
也可寫成:
func1(a,b)
int a;
int b;
{
…
}
例5-1:給出以下程序的運行結果。
#include"iostream.h"
int func(int n)
{if(n>0)
return 1;
else if(n==0)
return 0;
else return -1;
}
void main()
{
int n;
cout<<"Please inputn:"<<endl;
cin>>n;
cout<<"\ntheresult:"<<func(n)<<endl;
}此程序的運行結果為:
Please input n:
2
the result:1
Please input n:
-2
theresult:-1
請注意:C++中不允許函數(shù)定義嵌套,即在函數(shù)定義中再定義一個函數(shù)是非法的。一個函數(shù)只能定義在別的函數(shù)的外部,函數(shù)定義之間都是平行的,互相獨立的。
例如:下面的代碼在主函數(shù)中非法嵌套了一個f()函數(shù)定義:
void main()
{
void f()
{
//…
}
}
5.3 函數(shù)原型
函數(shù)聲明也稱函數(shù)模型(或函數(shù)原型)。在主調函數(shù)中,如果要調用另一個函數(shù),則須在本函數(shù)或本文件中的開頭將要被調用的函數(shù)事先作一聲明。聲明函數(shù),就是告訴編譯器函數(shù)的返回類型、名稱和形參表構成,以便編譯系統(tǒng)對函數(shù)的調用進行檢查。
函數(shù)聲明的一般格式為:
函數(shù)類型 函數(shù)名(形式參數(shù)表);
除了需在函數(shù)聲明的末尾加上一個分號“;”之外,其他的內容與函數(shù)定義中的第一行(稱函數(shù)頭)的內容一樣。
例如:設有一函數(shù)的定義為:
double func1(double a, int b, float c)
{
函數(shù)體
}
正確完整的函數(shù)聲明應為:
doublefunc1(double x, int y, float z);
//末尾要加上分號
也可以寫為如下形式:
double func1(double,int,float);
//函數(shù)聲明中省略了形參名
或寫為如下形式:
double func1(double a, int b, float c);
//函數(shù)聲明中的形參名與
函數(shù)定義中的形參名不同
不能寫為如下形式:
doublefunc1(x,y,z); //函數(shù)聲明中省略了形參類型
或:
func1(double x, int y, float z);
//函數(shù)聲明中省略了函數(shù)類型
或:
double func1(int y, float z, double x);
//函數(shù)聲明中形參順序調換了
5.4 函數(shù)的調用
在C++中,除了主函數(shù)main由系統(tǒng)自動調用外,其他函數(shù)都是由主函數(shù)直接或間接調用的。函數(shù)調用的語法格式為:
函數(shù)名 (實際參數(shù)表);
實參應該與函數(shù)定義中的形參表中的形參一一對應,即個數(shù)相等、次序一致且對應參數(shù)的數(shù)據(jù)類型相同或相容。每個實參是一個表達式,并且必須有確定的值。
如:
g1(25) //實參是一個整數(shù)
g2(x) //實參是一個變量
g3(a,2*b+3) //第一個為變量,第二個運算表達式
g4(sin(x),’@’) //第一個為函數(shù)調用表達式,第二個為字符常量
g5(&d,*p,x/y-1)//分別為取地址運算、間接訪問和一般運算表達式
常見的函數(shù)調用方式有下列兩種:
方式一:將函數(shù)調用作為一條表達式語句使用,只要求函數(shù)完成一定的操作,而不使用其返回值。若函數(shù)調用帶有返回值,則這個值將會自動丟失。例如:
max(3,5);
方式二:對于具有返回值的函數(shù)來說,把函數(shù)調用語句看作語句一部分,使用函數(shù)的返回值參與相應的運算或執(zhí)行相應的操作。例如:
inta=max(3,5);
inta=max(3,5)+1;
cout<<max(3,5)<<endl;
if(f1(a,b))cout<<”true”<<endl;
inta=2; a=max(max(a,3),5);
1.C++的函數(shù)調用過程,需要調用初始化和善后處理的環(huán)節(jié)。函數(shù)調用的整個過程就是??臻g操作的過程。
2.函數(shù)的棧操作原理是一樣的,但具體的實現(xiàn)因編譯器不同而不同。
#include<iostream.h>
int max(int a,int b,int c)
{
int t;
t=a;
if(b>t) t=b;
if(c>t) t=c;
return t;
}
void main()
{
int x,y,z;
cout<<"input x y z:"
<<endl;
cin>>x>>y>>z;
int m=max(x,y,z);
cout<<”The max is:”
<<m
<<endl;
}
當調用一個函數(shù)時,整個調用過程分為三步進行,第一步是參數(shù)傳遞,第二步是函數(shù)體執(zhí)行,第三步是返回,即返回到函數(shù)調用表達式的位置。
參數(shù)傳遞稱為“實虛結合”,即實參向形參傳遞信息,使形參具有確切地含義(即具有對應的存儲空間和初值)。這種傳遞又分為兩種不同的方式,一種是按值傳遞,另一種是地址傳遞或引用傳遞。
1. 按值傳遞
以按值傳遞方式進行參數(shù)傳遞的過程為:首先計算出實參表達式的值,接著給對應的形參變量分配一個存儲空間,該空間的大小等于該形參類型的長度,然后把已求出的實參表達式的值一一存入到為形參變量分配的存儲空間中,成為形參變量的初值,供被調用函數(shù)執(zhí)行時使用。這種傳遞是把實參表達式的值傳送給對應的形參變量,故稱這種傳遞方式為“按值傳遞”。這種方式被調用函數(shù)本身不對實參進行操作,也就是說,即使形參的值在函數(shù)中發(fā)生了變化,實參的值也完全不會受到影響,仍為調用前的值。
例5-3:按值傳遞。
#include "iostream.h"
void swap(int,int);
void main()
{
int a=3,b=4;
cout<<"a="<<a<<",b=“
<<b<<endl;
swap(a,b);
cout<<"a="<<a<<",b="
<<b<<endl;
}
voidswap(int x,int y)
{
int t=x;
x=y;
y=t;
}
此程序的運行結果為:
a=3,b=4
a=3,b=4
2. 地址傳遞
如果在函數(shù)定義時將形參的類型說明成指針,對這樣的函數(shù)進行調用時就需要指定地址值形式的實參。這時的參數(shù)傳遞方式即為地址傳遞方式。這種地址傳遞與上述的按值傳遞不同,它把實參的存儲地址傳送給對應的形參,從而使得形參指針和實參指針指向同一個地址。因此,被調用函數(shù)中對形參指針所指向的地址中內容的任何改變都會影響到實參。
例5-4:地址傳遞。
#include "iostream.h"
void swap(int *,int *);
void main()
{
int a=3,b=4;
cout<<"a="<<a<<",b=“
<<b<<endl;
swap(&a,&b);
cout<<"a="<<a<<",b=“
<<b<<endl;
}
voidswap(int *x,int *y)
{
int t=*x;
*x=*y;
*y=t;
}
此程序的運行結果為:
a=3,b=4
a=4,b=3
3. 引用傳遞
按值傳遞方式容易理解,但形參值的改變不能對實參產生影響;地址傳遞方式雖然可以使得形參的改變對相應的實參有效,但如果在函數(shù)中反復利用指針進行間接訪問,會使程序容易產生錯誤且難以閱讀。如果以引用作為參數(shù),則既可以使得對形參的任何操作都能改變相應的實參的數(shù)據(jù),又使函數(shù)調用顯得方便、自然。引用傳遞方式是在函數(shù)定義時在形參前面加上引用運算符“&”。
例5-5:引用傳遞。
#include "iostream.h"
void swap(int &,int &);
void main()
{
int a=3,b=4;
cout<<"a="<<a<<",b=“
<<b<<endl;
swap(a,b);
cout<<"a="<<a<<",b=“
<<b<<endl;
}
voidswap(int &x,int &y)
{
int t=x;
x=y;
y=t;
}
此程序的運行結果為:
a=3,b=4
a=4,b=3
由前述可知,C++函數(shù)不能嵌套定義,即一個函數(shù)不能在另一個函數(shù)體中進行定義。但在使用時,允許嵌套調用,即在調用一個函數(shù)的過程中又調用另一個函數(shù)。 例如:
func1(int a, float b)
{ float c;
c=func2(b-1,b+1);
}
int func2(float x, float y)
{
函數(shù)體
}
func1和func2是分別獨立定義的函數(shù),互不從屬。
一個函數(shù)直接或間接地調用自身,這種現(xiàn)象就是函數(shù)的遞歸調用。
遞歸調用有兩種方式:直接遞歸調用和間接遞歸調用。直接遞歸調用即在一個函數(shù)中調用自身,間接遞歸調用即在一個函數(shù)中調用了其他函數(shù),而在該其他函數(shù)中又調用了本函數(shù)。
利用函數(shù)的遞歸調用,可將一個復雜問題分解為一個相對簡單且可直接求解的子問題(“遞推”階段);然后將這個子問題的結果逐層進行回代求值,最終求得原來復雜問題的解(“回歸”階段)。
例5-12:求n的階乘。(函數(shù)遞歸調用的例程。)
#include "iostream.h"
long f(int n)
{if(n<0)
{cout<<“error!“
<<endl;
return(-1);}
else if(n<=1)
return(1);
else
return (n*f(n-1));
}
voidmain()
{long f(int n);
int n;
cout<<"input n:"
<<endl;
cin>>n;
cout<<"n!="<<f(n)
<<endl;
}
此程序的運行結果為:
please input n:
5
n!=120
5.5變量的作用域與生存期
1.程序的內存區(qū)域。
一個程序將操作系統(tǒng)分配給其運行的內存塊分為4個區(qū)域。
(1)代碼區(qū),存放程序的代碼,即程序中各個函數(shù)中的代碼塊。
(2)全局數(shù)據(jù)區(qū),存放程序全局數(shù)據(jù)和靜態(tài)數(shù)據(jù)。
(3)堆區(qū),存放程序的動態(tài)數(shù)據(jù)。
(4)棧區(qū),存放程序的局部數(shù)據(jù),即各個函數(shù)中的數(shù)據(jù)。
2.局部變量。
在一個函數(shù)內部說明的變量是內部變量,它只在該函數(shù)范圍內有效。也就是說,只有在包含變量說明的函數(shù)內部,才能使用被說明的變量,在此函數(shù)之外就不能使用這些變量了。所以內部變量也稱“局部變量”。
P83 ch5_1.cpp
關于局部變量的作用域還要說明以下幾點:
1.主函數(shù)main()中定義的內部變量,也只能在主函數(shù)中使用,其它函數(shù)不能使用。同時,主函數(shù)中也不能使用其它函數(shù)中定義的內部變量。因為主函數(shù)也是一個函數(shù),與其它函數(shù)是平行關系。這一點是與其它語言不同的,應予以注意。
2.形參變量也是內部變量,屬于被調用函數(shù);實參變量,則是調用函數(shù)的內部變量。
3.允許在不同的函數(shù)中使用相同的變量名,它們代表不同的對象,分配不同的單元,互不干擾,也不會發(fā)生混淆。
4.在復合語句中也可定義變量,其作用域只在復合語句范圍內。
3.全局變量
(1)在函數(shù)外部定義的變量稱為外部變量。以此類推,在函數(shù)外部定義的數(shù)組就稱為外部數(shù)組。
(2)外部變量不屬于任何一個函數(shù),其作用域是:從外部變量的定義位置開始,到本文件結束為止。
(3)外部變量可被作用域內的所有函數(shù)直接引用,所以外部變量又稱全局變量。
例:輸入長方體的長(l)、寬(w)、高(h),求長方體體積及正、側、頂三個面的面積。
int s1,s2,s3;
int vs(int a,int b,int c)
{ int v;
v=a*b*c; s1=a*b; s2=b*c; s3=a*c;
return v;
}
main()
{int v,l,w,h;
clrscr();
printf("\ninput length,width and height: ");
scanf("%d%d%d",&l,&w,&h);
v=vs(l,w,h);
printf("v=%d s1=%d s2=%d s3=%d\n",v,s1,s2,s3);
getch();
}
對于全局變量還有以下幾點說明:
(1)外部變量可加強函數(shù)模塊之間的數(shù)據(jù)聯(lián)系,但又使這些函數(shù)依賴這些外部變量,因而使得這些函數(shù)的獨立性降低。
從模塊化程序設計的觀點來看這是不利的,因此不是非用不可時,不要使用外部變量。
(2)在同一源文件中,允許外部變量和內部變量同名。在內部變量的作用域內,外部變量將被屏蔽而不起作用。
(3)外部變量的作用域是從定義點到本文件結束。如果定義點之前的函數(shù)需要引用這些外部變量時,需要在函數(shù)內對被引用的外部變量進行說明。外部變量說明的一般形式為:
extern 數(shù)據(jù)類型 外部變量[,外部變量2……];
注意:外部變量的定義和外部變量的說明是兩回事。外部變量的定義,必須在所有的函數(shù)之外,且只能定義一次。而外部變量的說明,出現(xiàn)在要使用該外部變量的函數(shù)內,而且可以出現(xiàn)多次。
1.定義格式: static 數(shù)據(jù)類型 內部變量表;
2.存儲特點
(1)靜態(tài)局部變量屬于靜態(tài)存儲。在程序執(zhí)行過程中,即使所在函數(shù)調用結束也不釋放。換句話說,在程序執(zhí)行期間,靜態(tài)內部變量始終存在,但其它函數(shù)是不能引用它們的。
(2)定義但不初始化,則自動賦以"0"(整型和實型)或'\0'(字符型);且每次調用它們所在的函數(shù)時,不再重新賦初值,只是保留上次調用結束時的值!
(3)何時使用靜態(tài)局部變量
需要保留函數(shù)上一次調用結束時的值。
變量只被引用而不改變其值。
1.構成一個程序的多個源文件之間,通過聲明數(shù)據(jù)或函數(shù)為外部的(extern)來進行溝通。
2.所有函數(shù)聲明一般都放在源文件的開始位置。
3.帶extern的是變量聲明,不是變量定義。
1.靜態(tài)全局變量
(1)在全局變量前加一個static,使該變量只在這個源文件中可用,稱之為全局靜態(tài)變量。全局靜態(tài)變量就是靜態(tài)全局變量。
(2)靜態(tài)全局變量對組成該程序的其他源文件是無效的。
2.靜態(tài)函數(shù)
函數(shù)的聲明和定義默認情況下在整個程序中是extern的。有時候,你可能需要使某個函數(shù)只在一個源文件中有效,不能被其他源文件所用,這時在函數(shù)前面加上static。
1.靜態(tài)生命期
這種生命期與程序的運行期相同,只要程序一開始運
行,這種生命期的變量就存在,當程序結束時,其生
命期就結束。
2.局部生命期
在函數(shù)內部聲明的變量或者是塊中聲明的變量具有局
部生命期。
3.動態(tài)生命期
這種生命期由程序中特定的函數(shù)調用(malloc()和
free())或操作符(new和delete)來創(chuàng)建和釋放。
隨機產生1~9之間的整數(shù)
#include<iostream.h>
#include<stdlib.h>
#include<iomanip.h>
#include<time.h>
void main()
{
srand(time(0));
for(inti=1;i<=10;i++)
{
cout<<setw(10)<<1+rand()%9;
if(i%5==0)
cout<<endl;
}
}
5.6 函數(shù)的作用域
1.局部作用域
當標識符的聲明出現(xiàn)在由一對花括號所括起來的一段程序(塊)內時,該標識符的作用域從聲明點開始,到塊結束處為止,該作用域的范圍具有局部性。
2.函數(shù)作用域
標號是唯一具有函數(shù)作用域的標識符。
3.函數(shù)原型作用域
函數(shù)原型聲明中所作的參數(shù)聲明在該作用域中。這個作用域開始于函數(shù)原型聲明的左括號,結束于函數(shù)聲明的右括號。
4.文件作用域
文件作用域是在所有函數(shù)定義之外說明的,其作用域從說明點開始,一直延伸到源文件結束。
可見性從另一角度表現(xiàn)標識符的有效性,標識符在某個位置可見,表示該標識符可以被引用??梢娦耘c作用域是一致的。作用域指的是標識符有效的范圍,而可見性是分析在某一位置標識符的有效性。
5.7 多文件結構
每個標準庫都有相應的“頭文件”,頭文件中包含對應庫中所有函數(shù)的函數(shù)原型和這些函數(shù)所需的各種數(shù)據(jù)類型和常量的定義。
程序員也可以自己定義頭文件,自定義的頭文件應以.h結尾。自定義的頭文件可以用#include來包含。
大程序傾向于分成多個源文件,其理由為:
(1)避免重復編譯函數(shù)。
(2)使程序更加容量管理。
(3)把相關函數(shù)放到一特定源文件中。
1.#include包含指令
(1)文件包含是指,一個源文件可以將另一個源文件的全部內容包含進來。
(2)文件包含的格式
#include “包含文件名” 或 #include <包含文件名>
兩種格式的區(qū)別僅在于:
①使用雙引號:系統(tǒng)首先到當前目錄下查找被包含文件,如果沒找到,再到系統(tǒng)指定的“包含文件目錄”(由用戶在配置環(huán)境時設置)去查找。
②使用尖括號:直接到系統(tǒng)指定的“包含文件目錄”去查找。一般地說,使用雙引號比較保險。
(3)文件包含的優(yōu)點
一個大程序,通常分為多個模塊,并由多個程序員分別編程。有了文件包含處理功能,就可以將多個模塊共用的數(shù)據(jù)(如符號常量和數(shù)據(jù)結構)或函數(shù),集中到一個單獨的文件中。這樣,凡是要使用其中數(shù)據(jù)或調用其中函數(shù)的程序員,只要使用文件包含處理功能,將所需文件包含進來即可,不必再重復定義它們,從而減少重復勞動。
(4)說明
①編譯預處理時,預處理程序將查找指定的被包含文件,并將其復制到#include命令出現(xiàn)的位置上。
②常用在文件頭部的被包含文件,稱為“標題文件”或“頭部文件”,常以“h”(head)作為后綴,簡稱頭文件。在頭文件中,除可包含宏定義外,還可包含外部變量定義、結構類型定義等。
③一條包含命令,只能指定一個被包含文件。如果要包含n個文件,則要用n條包含命令。
④文件包含可以嵌套,即被包含文件中又包含另一個文件。
2.#define宏定義指令
(1) #define最常用的方法是建立常量,但已被C++的const定義語句所代替。
(2) #define還可以定義帶參的宏,但也已被C++的inline內嵌函數(shù)所代替。
(3) #define的一個有效的使用是在條件編譯指令中。
3.條件編譯指令
條件編譯可有效地提高程序的可移植性,并廣泛地應用在商業(yè)軟件中,為一個程序提供各種不同的版本。
(1)一般格式
#ifdef 標識符
程序段1;
[#else
程序段2;]
#endif
(2)功能:當“標識符”已經被#define命令定義過,則編譯程序段1,否則編譯程序段2。
①在不同的系統(tǒng)中,一個int 型數(shù)據(jù)占用的內存字節(jié)數(shù)可能是不同的。
②利用條件編譯,還可使同一源程序即適合于調試(進行程序跟蹤、打印較多的狀態(tài)或錯誤信息),又適合高效執(zhí)行要求。
(3)關于#ifndef ~ #endif命令
格式與#ifdef ~ #endif命令一樣,功能正好與之相反。
5.8 內聯(lián)函數(shù)
內聯(lián)擴展(inline expansion)簡稱為內聯(lián)(inline),內聯(lián)函數(shù)也稱為內嵌函數(shù)。當在一個函數(shù)的定義或聲明前加上關鍵字inline則就把該函數(shù)定義為內聯(lián)函數(shù),它主要是解決程序的運行效率。
計算機在執(zhí)行一般函數(shù)的調用時,無論該函數(shù)多么簡單或復雜,都要經過參數(shù)傳遞、執(zhí)行函數(shù)體和返回等操作,這些操作都需要一定的時間開銷。若把一個函數(shù)定義為內聯(lián)函數(shù)后,在程序編譯階段,編譯器就會把每次調用該函數(shù)的地方都直接替換為該函數(shù)體中的代碼,由此省去函數(shù)的調用及相應的保存現(xiàn)場、參數(shù)傳遞和返回操作,從而加快整個程序的執(zhí)行速度。
例5-6:
#include "iostream.h"
inline int abs(int x)
{
return x<0?-x:x;
}
void main()
{
int a,b=3,c,d=-4;
a=abs(b);
c=abs(d);
cout<<"a="<<a<<",c="<<c<<endl;
}
此程序的運行結果為:a=3,c=4
5.9 函數(shù)重載
函數(shù)重載又稱為函數(shù)的多態(tài)性,是指同一個函數(shù)名對應著多個不同的函數(shù)。所謂“不同”是指這些函數(shù)的形參表必須互不相同,或者是形參的個數(shù)不同,或者是形參的類型不同,或者是兩者都不相同,否則將無法實現(xiàn)函數(shù)重載。例如,下面是合法的重載函數(shù):
intfunc1(int,int);
intfunc1(int);
doublefunc1(int,long);
doublefunc1(long);
重載函數(shù)的類型,即函數(shù)的返回類型可以相同,也可以不同。但如果僅僅是返回類型不同而函數(shù)名相同、形參表也相同,則是不合法的,編譯器會報“語法錯誤”。如:
intfunc1(int a, int b);
doublefunc1(int a, int b);
除形參名外都相同的情況 ,編譯器不認為是重載函數(shù) ,只認為是對同一個函數(shù)原型的多次聲明。
在調用一個重載函數(shù)func1()時,編譯器必須判斷函數(shù)名func1到底是指哪個函數(shù)。它是通過編譯器,根據(jù)實參的個數(shù)和類型對所有func1()函數(shù)的形參一一進行比較,從而調用一個最匹配的函數(shù)。
5.10 帶默認形參值的函數(shù)
在C++語言中調用函數(shù)時,通常要為函數(shù)的每個形參給定對應的實參。若沒有給出實參,則按指定的默認值進行工作。
當一個函數(shù)既有定義又有聲明時,形參的默認值必須在聲明中指定,而不能放在定義中指定。只有當函數(shù)沒有聲明時,才可以在函數(shù)定義中指定形參的默認值。
默認值的定義必須遵守從右到左的順序,如果某個形參沒有默認值,則它左邊的參數(shù)就不能有默認值。
如:
void func1(int a, double b=4.5, int c=3);//合法
void func1(int a=1, double b, intc=3); //不合法
在進行函數(shù)調用時,實參與形參按從左到右的順序進行匹配,當實參的數(shù)目少于形參時,如果對應位置形參又沒有設定默認值,就會產生編譯錯誤;如果設定了默認值,編譯器將為那些沒有對應實參的形參取默認值。
注意:形參的默認值可以是全局常量、全局變量、表達式、函數(shù)調用,但不能為局部變量。
例如,下例不合法:
void func1()
{
int k;
void g(int x=k); //k為局部變量
}
聯(lián)系客服