今天寫程序時發現一個小問題,如下:
1 #include<iostream>
2 #include<stdlib.h>
3
4 using namespace std;
5 template<class T>
6 class Node
7 {
8 private:
9 Node<T> *next;
10 public:
11 T data;
12 Node(const T& item,Node<T>* ptrnext=NULL);
13 void InsertAfter(Node<T> *p);
14 Node<T> *DeleteAfter(void);
15 Node<T> *NextNode(void)const;
16 };
17
18 template<class T>
19 Node<T>::Node(const T& item,Node<T>* ptrnext=NULL):data(item),next(ptrnext){}
20
21 template<class T>
22 Node<T> *Node<T>::NextNode(void)const
23 {
24 return next;
25 }
26
27 int main(void)
28 {
29 return 1;
30 }
編譯時發生如下錯誤:
經過查找發現如果在類定義中已經聲明函數參數的默認值則在函數體重就不用再聲明,於是更改代碼如下:
1 #include<iostream>
2 #include<stdlib.h>
3
4 using namespace std;
5 template<class T>
6 class Node
7 {
8 private:
9 Node<T> *next;
10 public:
11 T data;
12 Node(const T& item,Node<T>* ptrnext=NULL);
13 void InsertAfter(Node<T> *p);
14 Node<T> *DeleteAfter(void);
15 Node<T> *NextNode(void)const;
16 };
17
18 template<class T>
19 Node<T>::Node(const T& item,Node<T>* ptrnext):data(item),next(ptrnext){}
20
21 template<class T>
22 Node<T> *Node<T>::NextNode(void)const
23 {
24 return next;
25 }
26
27 int main(void)
28 {
29 return 1;
30 }
下面是對這個問題的一個詳細解釋,轉自:http://blog.csdn.net/vlily/article/details/7247888
我們可以賦予函數參數默認值。所謂默認值就是在調用時,可以不寫某些參數的值,編譯器會自動把默認值傳遞給調用語句中。默認值可以在聲明或定義中設置;也可在聲明或定義時都設置,都設置時要求默認值是相同的。
關於默認值要注意幾點:
1.若在定義時而不是在聲明時置默認值,那么函數定義一定要在函數的調用之前。因為聲明時已經給編譯器一個該函數的向導,所以只在定義時設默認值時,編譯 器只有檢查到定義時才知道函數使用了默認值。若先調用后定義,在調用時編譯器並不知道哪個參數設了默認值。所以我們通常是將默認值的設置放在聲明中而不是 定義中。
2.不能將實際值傳遞給引用類型的參數。可以將變量作引用類型參數的默認值,這時變量必須是已經聲明且是全局變量。
聲明函數時,要將類或結構中定義 的靜態成員變量作為默認值,若該類或結構還未創建實例,那要在此靜態成員變量前加上作用域操作符(::)。
若已聲明了類或結構的實例,則引用其成員變量作為函數參數的默認值,就要在變量前加上實例名和成員操作符(.)。
3.若給某一參數設置了默認值,那么在參數表中其后所有的參數都必須也設置默認值,否則,由於函數調用時可不列出已設置默認值的參數,編譯器無法判斷在調用時是否有參數遺漏。
4.在調用時,若給已經設置默認值的參數傳遞實際值,既要取代默認值,則在參數表中被取代參數的左邊所定義的所有參數,無論是否有默認值,都必須傳遞實際參數。
這也是因為函數調用時可不列出已設置默認值的參數。假若被取代參數的左邊既有設置了默認值的參數也有未設置默認值的參數,若不對其左邊的所有參數傳遞實際參數,編譯器也就無法分辨傳遞的這個取代值到底要傳遞給哪個參數。
例如有以下函數聲明:
int FunctionOne(int x,int y=0,int z=0,int w=0);
我們要給z 傳遞整型值8,作如下調用:
FunctionOne(8);
顯然,編譯器無法確定這個8 到底要傳遞給哪個參數。為了達到我們的目的,必須這樣調用:
FunctionOne(0,0,8);
這是x 被傳遞了0,y 被傳遞了 0,z 被傳遞了8
---------------------------------------------------------------------------------------------------------------
第九節 默認參數的函數
1.默認參數的目的
C++可以給函數定義默認參數值。通常,調用函數時,要為函數的每個參數給定對應的實參。例如:
void delay(int loops); //函數聲明
void delay(int loops) //函數定義
{
if(100ps==0)
return;
for(int i=0;i<loops,i++);
}
無論何時調用delay()函數,都必須給loops傳一個值以確定時間。但有時需要用相同的實參反復調用delay()函數。C++可以給參數定義默認值。如果將delay( )函數中的loops定義成默認值1000, 只需簡單地把函數聲明改為:
void delay(int loops=1000);
這樣,無論何時調用delay()函數,都不用給loops賦值,程序會自動將它當作值1000進行處理。例如,調用:
delay(2500); //loops設置為2500
delay(); //ok:loops采用默認值1000
調用中,若不給出參數,則按指定的默認值進行工作。
允許函數默認參數值,是為了讓編程簡單,讓編譯器做更多的檢查錯誤工作。
2.默認參數的聲明
默認參數在函數聲明中提供,當又有聲明又有定義時,定義中不允許默認參數。如果函數只有定義,則默認參數才可出現在函數定義中。例如:
void point(int=3,int=4); //聲明中給出默認值
void point(intx,inty) //定義中不允許再給出默認值
{
cout <<x<<endl;
cout <<y<<endl;
}
3.默認參數的順序規定
如果一個函數中有多個默認參數,則形參分布中,默認參數應從右至左逐漸定義。當調用函數時,只能向左匹配參數。例如:
void func(int a=1,int b,int c=3, int d=4); //error
void func(int a, int b=2,int c=3,int d=4); //ok
對於第2個函數聲明,其調用的方法規定為:
func(10,15,20,30); //ok:調用時給出所有實參
func(); //error:參數a沒有默認值
func(i2,12); //ok:參數c和d默認
func(2,15,20); //error:只能從右到左順序匹配默認
4.默認參數與函數重載
默認參數可將一系列簡單的重載函數合成為一個。例如, 下面3個重載函數:
void point(int,int){//...}
void point(int a){return point(a,4);}
void point(){return point(3,4);}
可以用下面的默認參數的函數來替代:
void point(int=3,int=4);
當調用“point();”時,即調用“point(3,4);” 它是第3個聲明的重載函數。
當調用“point(6);”時,即調用“point(6,4);”,它是第2個聲明的重載函數。
當調用“point(7,8);”時,即調用第1個聲明的重載函數
如果一組重載函數(可能帶有默認參數)都允許相同實參個數的調用,將會引起調用的二義性。例如:
void func(int); //重載函數之一
void func(int,int=4); //重載函數之二,帶有默認參數
void func(int=3,int=4); //重載函數之三,帶有默認參數
func(7); //error: 到底調用3個重載函數中的哪個?
func(20,30) //error:到底調用后面2個重載函數的哪個?
5.默認值的限定
默認值可以是全局變量、全局常量,甚至是一個函數。例如:
int a=1;
int fun(int);
int g(int x;fun(a)); //ok:允許默認值為函數
默認值不可以是局部變量,因為默認參數的函數調用是在編譯時確定的,而局部變量的位置與值在編譯時均無法確定。例如:
void fun()
{
int i;
void g(int x=i); //error:處理g()函數聲明時,i不可見
}
本章小結
隨着程序量和程序復雜度的不斷增加,最好的辦法是把程序分成更小,更容易管理的模塊,這種模塊就是函數。
函數名最好能反映出所要完成的任務。
函數可以把數據返回給調用者,若函數要返回一個值,必須在函數名前規定返回值的類型,若函數沒有返回值,則類型為void。
程序通過參數把信息傳遞給函數,若函數需要接受參數,就必須給參數指定名稱及類型。
C++必須知道函數的返回類型以及接受的參數個數和類型, 如果函數的定義出現在函數調用之后,就必須在程序的開始部分用函數原型進行聲明。
局部變量是在函數內部定義的,只能被定義該變量的函數訪問。全局變量是指其作用域貫穿程序始終的變量。定義全局變量要在程序開始時進行,並且放在所有函數的外面。
靜態局部變量是在函數內部定義,但生命期卻隨函數的第一次被調用而產生, 隨程序的結束而結束, 靜態局部變量只能在定義該變量的函數中可見。
函數調用機制是由棧操作的過程實現的。函數可以遞歸調用。函數定義不能放在任何函數定義的里面。
內聯函數是為了提高編程效率而實現的, 它克服了用#define宏定義所帶來的弊病。
函數重載允許用同一個函數名定義多個函數。連接程序會根據傳遞給函數的參數數目、類型和順序調用相應的函數。函數重載使程序設計簡單化,程序員只要記住一個函數名,就可以完成一系列相關的任務。
在函數定義中通過賦值運算,即可指定默認參數值。一旦程序在調用函數時默認了參數值, 函數就使用默認參數值。 不允許在參數中間使用默認值。指定默認參數值可以使函數的使用更為簡單,同時也增強了函數的可重用性。