1. 程式人生 > >c++ primer plus 第六版 第八章 學習筆記

c++ primer plus 第六版 第八章 學習筆記

1、引用變數(&左值引用)

   1)必須在建立引用變數時對其初始化,且初始化後不能再將其作為另一個變數的引用變數;

   2)當函式的形參為引用變數時,在函式呼叫時即將引用形參初始化為實參,傳遞方式類似於地址傳遞,該引用變數的改變將引起原始變數的改變;

   3)函式形參為引用變數時,若傳遞的實參型別不匹配或者不是左值時,將建立一個型別匹配或者匿名的臨時變數(同時發出警告),此時引用變數將不再指向實參而是臨時變數,該臨時變數只在函式呼叫期間存在,並且此時引用變數的變化將不會導致實參的變化;

   4)一般而言,當形參為const的引用函式時,若實參與形參的型別不匹配,系統將建立臨時變數,因為此時的函式一般只用作值傳遞而不改變實參的值,臨時變數的建立使其更通用;而當形參不是用const宣告的引用變數函式時,編譯器一般將會認為錯誤,因為此時函式一般用於改變實參的值,臨時變數的建立可能導致結果不是預期的。(Visual Studio 2017 不允許建立臨時變數)

   5)&&可用於右值的引用;

6)用const宣告的引用傳遞結構時類似於值傳遞,不能改變原始結構的值,但採用引用的方法更節省時間和記憶體

7)函式形參為引用變數時,函式呼叫仍與普通函式相同,若有函式呼叫sweap(&a),(原型為void sweap(int &))則為錯誤的呼叫,函式呼叫時的&表示地址運算子而不是引用運算子。

2、預設引數

   1)指函式原型中,將形參列表中的一個或多個引數賦值,當呼叫函式時,既可以對賦值過的形參重新賦值,也可以不指定對應的實參而採用預設的引數;

2)只能在引數列表中從右到左提供預設引數,即如果為某個引數提供了預設值,則必須為引數右邊所有的引數提供預設值

3)預設引數是在函式宣告中體現的,函式定義與沒有預設引數時完全相同,如果也在函式定義時指定預設引數,會出現“重定義預設引數“的錯誤;而如果只在函式定義時對其中引數指定確定值,則沒有什麼意義,函式與沒有預設引數時一樣的呼叫,實參值將代替定義時指定的值。

3、函式過載

多於函式特徵標不同而函式名稱相同的函式,在函式呼叫時根據實參的不同而呼叫不同的同名函式的功能。

  1. 函式特徵標:引數列表;當多個函式的引數列表數目、型別、排列順序均相同時,則視為其函式特徵標相同。
  2. 型別引用和型別視為同一個特徵標,即:double cube(double x)與double cube( double &x)不能進行函式過載,視為一個函式,特徵標相同
  3. Const和非const引數視為不同的特徵標,即:double cube(const double * x)與

double cube(double * x)可以發生函式過載,根據實參的型別進行函式呼叫。

  1. 非const引數函式也可以接受const實參,即:若只有double cube(double *x)函式,當實參為const和非const時都將呼叫該函式,非canst形參可以接受const和非const實參,但const形參只能接受const實參;但當有兩個同名的函式引數分別為const和非const時,便只能接受與形參相同型別的實參
  2. 是特徵標的不同使得可以對函式進行過載,而不是函式型別;即當函式名、特徵標相同而返回值不同時,是不允許函式過載的,即:long gronk(int n)與double grank(int n)不能進行函式過載,特徵標相同,不允許同時定義這樣兩個函式;long gronk(int n)與double gronk(float n)可以進行函式過載,因為特徵標不同;即函式過載必須滿足的兩個要素:函式名相同,特徵標不同;    
  1. 函式模板

當函式的功能相同但引數型別不同時,可以定義一個函式模板;與常規的函式時定義的異同:

  1. 其函式原型須加一行:typename(或者class)<typename T>只有T為可以自己命名的(表示引數型別),定義函式時T替換常規函式定義時的引數型別;即函式原型為:template <typename T>

            Void Swep(T &a,T&b)//Swep為函式名,括號內為引數列表

  1. 呼叫函式時,與常規函式呼叫相同,即:swep(實參列表)
  2. 函式模板並不能縮短可執行的程式,編譯器將會根據實參的不同生成多個函式,再對其呼叫,與定義對個函式效果相同,函式模板使程式更簡潔
  3. 模板函式允許非模板引數型別(泛型)的引數,即允許

Template

 <typename T>

            Void Swep(T &a,T&b,int)

  1. 模板函式也允許函式過載,即相同的模板函式名稱,但是同樣特徵標必須不同;
  2. 模板函式並不是函式定義,當提供特定的引數使用模板函式時,編譯器將自動進行隱式例項化,定義一個與提供的引數型別相匹配的函式;也可以在使用函式時進行顯示例項化,告訴編譯器需要定義的函式引數型別;顯式與隱式例項化都是使用所定義的模板函式演算法,當所需要的演算法不同而函式名稱以及引數與模板函式匹配時,可以進行顯示具體化,重新定義一個確定引數型別的演算法函式;
  3. 在編譯器選擇函式原型時,當函式名稱、引數型別都相同時,非模板函式優於顯示具體化函式優於使用模板的例項化;但當有函式呼叫lesser<>(m,n)時表示使用模板函式,此時即使有與其匹配的非模板函式仍編譯器將選擇模板函式,也可以在<>中指定要例項化函式型別;即對函式呼叫lesser(m,n)時非模板函式優先於模板函式,對函式呼叫lesser<>(m,n)限定於模板函式,此時模板函式優於非模板,且仍有模板具體化優於模板例項化;

問題:

1、&運算子:引用與地址運算子的差別,void sweap(int &a)只能表示形參為引用變數嗎,還是可以表示傳遞的是變數a的地址;函式原型中的&表示引用,而函式呼叫中的&表示地址運算子。

2、函式模板問題:

Void std::swap(_Ty&,_Ty&)表示標準庫中的函式,這個錯誤在於定義了一個與標準函式相同函式名和特徵標的函式,無法進行函式過載,解決辦法:更改定義的函式名;不使用標準庫