C++篇:第四章_函式_知識點大全

Oten發表於2022-04-10

五、函式

(一)函式使用規則

  1. 函式的定義不能巢狀但呼叫可以巢狀

  2. 在函式呼叫時,如某一預設引數要指明一個特定值,則有其之前所有引數都必須賦值

  3. 賦預設實參時 一旦某個形參被賦予了預設值,它後面的所有形參都必須有預設值,因為設定預設引數的順序是自右向左;且注意預設值不可以是區域性變數

  4. 函式引數的預設值可以是表示式

  5. 如果在函式定義時設定了預設引數,則就不能在函式宣告時再次設定,反之亦然

  6. 函式只有一個 返回值,除void型別函式

  7. 函式呼叫可以出現在執行語句中,也可以出現在表示式中,甚至還可以作為一個函式的實參,但不可作為函式的形參,因為函式返回值存在暫存器中, 沒有地址, 不能作為形參

  8. 函式是一種特殊的資料型別,正確

  9. 當函式不是void型別且函式體內沒有return語句時,此時函式的返回值與返回型別相同但內容卻是隨機的一個值

  10. C++所有的函式本質上都是外部函式(可延申至其他檔案中使用),故extern關鍵字可省略

  11. 如果函式的形參是指向普通變數的指標變數,實參只能用指向普通變數的指標,不能用指向const變數的指標,反之則都可以用

  12. 當函式自變數個數不確定時,系統不自動檢測自變數

13. 函式三種傳參:

① 值傳遞:會為形參重新分配記憶體空間 ,將實參的值拷貝給形參,形參的改變不會影響實參的值,函式被呼叫結束後,形參被釋放。

② 地址的傳遞:形參為指標變數,將實參的地址傳遞給函式,可以在函式中改變實參的值。呼叫時為形參指標變數分配記憶體,結束時釋放指標變數。

③ 引用傳遞:不會為形參重新分配記憶體空間,形參只是實參的別名,形參的改變只會影響實參的值,函式呼叫結束後,形參不會被釋放。

(二)函式的使用

  1. 建立自定義函式,呼叫時只需要明白函式的功能即可,故提高了程式的可讀性

  2. sizeof 返回的值表示的含義如下(單位位元組):

​ 陣列 —— 編譯時分配的陣列空間大小;
​ 指標 —— 儲存該指標所用的空間大小(儲存該指標的地址的長度,是長整型,應該為 4 );
​ 型別 —— 該型別所佔的空間大小;
​ 物件 —— 物件的實際佔用空間大小;

​ 函式 —— 函式的返回型別所佔的空間大小。函式的返回型別不能是 void

  1. sizeof(float)是(整型)型別表示式

  2. Math.floor() 表示向下取整,返回double型別

​ Math.ceil() 表示向上取整,返回double型別

​ Math.round() 四捨五入,返回int型別

  1. 使用者可以過載(不能重定義)標準庫函式,若如此,該函式將失去原有含義;但若已包含標準庫標頭檔案及相關名稱空間,則系統不允許使用者重新定義標準庫函式,因為兩個相同作用域內的函式 如果除了返回值型別外 的函式要素都相同 那麼編譯器會報重定義錯誤

  2. 函式返回值作為右值,被const修飾無效,故此時const相當於沒修飾

  3. 如果引數型別不一致,則函式呼叫時按形參型別隱式型別轉換實參

  4. main函式預設返回一個int型別的值

  5. 將一個字串傳遞到函式中,傳遞的是地址,則函式形參既可以用字元陣列,又可以用指標變數

  6. 函式的返回值可以是引用型別且函式返回引用可以作為左值

  7. 函式的返回型別可以是結構體型別,這時函式將返回一個結構體物件

  8. 所有的函式在定義它的程式中都是可見的

(三)預處理命令(包括巨集定義)

  1. 預處理命令列不能以分號結尾

  2. 預處理命令列可以出現在程式的最後一行

  3. 預處理命令列作用域是從出現位置開始到源程式檔案末尾

  4. 凡是以#號開頭的行,不一定都為編譯預處理命令列

  5. 在原始檔的一行上不可以有多條預處理命令

  6. 預處理不做語法檢查

  7. C++在編譯前由前處理器對預處理命令進行處理(故在編譯前被執行),編譯時進行語法分析

  8. 巨集替換不佔用程式的執行時間,只佔編譯時間

(四)行內函數與巨集的區別

  1. 行內函數在執行時可除錯,而巨集定義不可以;
  2. 編譯器會對行內函數的引數型別做安全檢查或自動型別轉換(同普通函式),而巨集定義則不會;
  3. 行內函數可以訪問類的成員變數,巨集定義則不能;
  4. 在類中宣告同時定義的成員函式,自動轉化為行內函數。

(五)函式與巨集的區別

  1. 巨集做的是簡單的字串替換(注意是字串的替換,不是其他型別引數的替換),而函式的引數的傳遞,引數是有資料型別的,可以是各種各樣的型別.

  2. 巨集的引數替換是不經計算而直接處理的,而函式呼叫是將實參的值傳遞給形參,既然說是值,自然是計算得來的.

  3. 巨集在編譯之前進行,即先用巨集體替換巨集名,然後再編譯的,而函式顯然是編譯之後,在執行時,才呼叫的.因此,巨集佔用的是編譯的時間,而函式佔用的是執行時的時間.

  4. 巨集的引數是不佔記憶體空間的,因為只是做字串的替換,而函式呼叫時的引數傳遞則是具體變數之間的資訊傳遞,形參作為函式的區域性變數,顯然是佔用記憶體的.

  5. 函式的呼叫是需要付出一定的時空開銷的,因為系統在呼叫函式時,要保留現場,然後轉入被呼叫函式去執行,呼叫完,再返回主調函式,此時再恢復現場,這些操作,顯然在巨集中是沒有的.

  6. 巨集替換不佔用程式的執行時間

  7. 巨集與型別無關,但是c++中函式必須指定返回型別,故巨集可以做函式不能做的事

(六)函式模板

1.函式模板的格式如下:

Template <class 形參名,class 形參名,......> 返回型別函式名(引數列表){函式體}

其中,class可以用typename關鍵字代替

  1. 函式模板呼叫時不需要顯式指定型別,系統自動匹配引數型別,若沒有合適的,會進行報錯。而類别範本使用需要顯式指定型別,且對於函式模板注意要返回值和引數的型別一致
  2. 模板函式和普通函式都符合條件時,優先執行普通函式
  3. 模板特化:(當函式模板需要對某些型別進行特化處理,稱為函式模板的特化,類别範本的特化同理)

① 因為很多時候,我們既需要一個模板能應對各種情形,又需要它對於某個特定的型別有著特別的處理,故出現了模板特化

① 特化整體上分為全特化和偏特化

② 全特化:就是模板中模板引數全被指定為確定的型別。 全特化也就是定義了一個全新的型別,全特化的類中的函式可以與模板類不一樣

③ 偏特化:模板中的模板引數沒有被全部確定,需要編譯器在編譯時進行確定

④ 對主版本模板類、全特化類、偏特化類的呼叫優先順序從高到低進行排序是:全特化類>偏特化類>主版本模板類

⑤ 當函式呼叫發現有特化後的匹配函式時,會優先呼叫特化的函式,而不再通過函式模版來進行例項化

⑥ 模板特化相當於在宣告瞭類别範本等後宣告需要模板特化然後讓接下來的程式碼自己使用一個型別,故不能單獨使用,例;![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps386C.tmp.jpg)

5. 模板特化實現:template<> + 完全和模板型別沒有一點關係的類實現或者函式定義;

① 特化為絕對型別(全特化):例:template<>class Compare{...}; // 特化為float型別,此為函式模板特化;函式模板只能全特化,沒有偏特化

② 特化為引用,指標型別(半特化、偏特化):例:template struct iterator_traits<_Tp*> {};

③ 特化為另外一個類别範本(偏特化):例:template class Compare<vector>{};

  1. 類别範本的成員函式都是函式模板;沒使用過的成員函式(即函式模板)不會被例項化
  2. 函式模板必須由程式設計師例項化為可執行的函式
  3. 函式模板的虛擬型別名是在編譯階段確定實際型別的

(七)函式過載

  1. 使用過載函式程式設計序的目的是:使用相同的函式名呼叫功能相似的函式;使用方便,提高可讀性

  2. 過載函式的形參(個數或型別)必須不同

  3. void x(int,char ch=’a’)與void x(int)可以在同一程式中定義,但不可以過載

(八)行內函數

1. 內聯(置)函式inline:

引入行內函數的目的是為了解決程式中函式呼叫的效率問題;程式在編譯器編譯的時候,編譯器將程式中出現的行內函數的呼叫表示式用行內函數的函式體進行替換,而對於其他的函式,都是在執行時候才被替代。這其實就是個空間代價換時間的節省(弊:程式碼被多次複製,增加了程式碼量,佔用更多的記憶體空間),故在當函式程式碼較小並且被頻繁呼叫的時候。在使用行內函數時要留神:

① 使用基類指標或引用來呼叫虛擬函式時,它都不能為行內函數(因為呼叫發生在執行時)。但是,使用類的物件(不是指標或引用)來呼叫時,可以當做是內聯,因為編譯器在編譯時確切知道物件是哪個類的

② 預設情況下,在類體中定義的成員函式若不包括迴圈等控制結構,符合行內函數要求時,C++會自動將它們作為行內函數處理(不是所有成員函式都是行內函數)

③ 行內函數在編譯時是將該函式的目的碼插入每個呼叫該函式的地方,不是執行時

④ 行內函數在編譯時做引數型別檢查

⑤ 在行內函數中不允許使用迴圈語句(for,while)和switch結果,帶有異常介面宣告的函式也不能宣告為行內函數。另外,遞迴函式(自己呼叫自己的函式)是不能被用來做行內函數的。行內函數只適合於只有1~5行的小函式

⑥ 行內函數的定義必須出現在行內函數第一次呼叫之前

⑦ 定義行內函數inline寫型別前面

⑧ 關鍵字inline 必須與函式定義體放在一起才能使函式成為內聯,僅將inline 放在函式宣告前面不起任何作用

⑨ 如果在類外定義inline函式,則必須將類定義和成員函式定義放在同一標頭檔案中,否則編譯時無法進行置換

⑩ 標頭檔案中不僅要包含 inline 函式的宣告,而且必須包含定義,且在定義時必須加上 inline

⑪ 不管是 class 宣告中定義的 inline 函式,還是 class 實現中定義的 inline 函式,不存在優先不優先的問題

⑫ 內建函式不需要使用堆疊進行現場的保護與恢復

⑬ 用 inline 修飾的函式原型其對應的函式也將成為行內函數 - 錯(自己理解:inline為建議型關鍵字)

⑭ 行內函數可以是靜態的

相關文章