1. 程式人生 > >C++函式系列篇:函式的預設值+帶預設引數的函式

C++函式系列篇:函式的預設值+帶預設引數的函式

我們可以賦予函式引數預設值。所謂預設值就是在呼叫時,可以不寫某些引數的值,編譯器會自動把預設值傳遞給呼叫語句中。預設值可以在宣告或定義中設定;也可在宣告或定義時都設定,都設定時要求預設值是相同的。

  關於預設值要注意幾點:

  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巨集定義所帶來的弊病。
  函式過載允許用同一個函式名定義多個函式。連線程式會根據傳遞給函式的引數數目、型別和順序呼叫相應的函式。函式過載使程式設計簡單化,程式設計師只要記住一個函式名,就可以完成一系列相關的任務。
  在函式定義中通過賦值運算,即可指定預設引數值。一旦程式在呼叫函式時默認了引數值, 函式就使用預設引數值。 不允許在引數中間使用預設值。指定預設引數值可以使函式的使用更為簡單,同時也增強了函式的可重用性。