首頁 > 軟體

C++中的函數知識點大全

2022-04-10 19:00:29

(一)函數使用規則

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

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

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

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

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

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

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

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

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

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

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

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

  • 函數三種傳參:

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

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

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

(二)函數的使用

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

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

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

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

  • sizeof(float)是(整型)型別表示式

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

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

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

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

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

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

  • main函數預設返回一個int型別的值

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

  • 函數的返回值可以是參照型別且函數返回參照可以作為左值

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

  • 所有的函數在定義它的程式中都是可見的

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

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

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

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

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

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

  • 預處理不做語法檢查

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

  • 宏替換不佔用程式的執行時間,只佔編譯時間

(四)行內函式與宏的區別

  • 行內函式在執行時可偵錯,而宏定義不可以;
  • 編譯器會對行內函式的引數型別做安全檢查或自動型別轉換(同普通函數),而宏定義則不會;
  • 行內函式可以存取類的成員變數,宏定義則不能;
  • 在類中宣告同時定義的成員函數,自動轉化為行內函式。

(五)函數與宏的區別

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

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

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

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

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

  • 宏替換不佔用程式的執行時間

  • 宏與型別無關,但是c++中函數必須指定返回型別,故宏可以做函數不能做的事

(六)函數模板

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

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

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

2.函數模板呼叫時不需要顯式指定型別,系統自動匹配引數型別,若沒有合適的,會進行報錯。而類別範本使用需要顯式指定型別,且對於函數模板注意要返回值和引數的型別一致

3.模板函數和普通函數都符合條件時,優先執行普通函數

4.模板特化:(當函數模板需要對某些型別進行特化處理,稱為函數模板的特化,類別範本的特化同理)

  • ① 因為很多時候,我們既需要一個模板能應對各種情形,又需要它對於某個特定的型別有著特別的處理,故出現了模板特化
  • ① 特化整體上分為全特化和偏特化
  • ② 全特化:就是模板中模板引數全被指定為確定的型別。 全特化也就是定義了一個全新的型別,全特化的類中的函數可以與模板類不一樣
  • ③ 偏特化:模板中的模板引數沒有被全部確定,需要編譯器在編譯時進行確定
  • ④ 對主版本模板類、全特化類、偏特化類的呼叫優先順序從高到低進行排序是:全特化類>偏特化類>主版本模板類
  • ⑤ 當函數呼叫發現有特化後的匹配函數時,會優先呼叫特化的函數,而不再通過函數模版來進行範例化
  • ⑥ 模板特化相當於在宣告了類別範本等後宣告需要模板特化然後讓接下來的程式碼自己使用一個型別,故不能單獨使用,例;![img](file:///C:UsersADMINI~1AppDataLocalTempksohtmlwps386C.tmp.jpg)

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

  • ① 特化為絕對型別(全特化):例:template<>class Compare{...}; // 特化為float型別,此為函數模板特化;函數模板只能全特化,沒有偏特化
  • ② 特化為參照,指標型別(半特化、偏特化):例:template struct iterator_traits<_Tp*> {};
  • ③ 特化為另外一個類別範本(偏特化):例:template class Compare<vector>{};

6. 類別範本的成員函數都是函數模板;沒使用過的成員函數(即函數模板)不會被範例化

7. 函數模板必須由程式設計師範例化為可執行的函數

8. 函數模板的虛擬型別名是在編譯階段確定實際型別的

(七)函數過載

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

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

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

(八)行內函式

內聯(置)函數inline:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

⑭ 行內函式可以是靜態的

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com