C 函式特性

2021-08-21 16:18:40 字數 4423 閱讀 3638

1、函式引數預設值

void fun(int i,int j=2,int k=3);

void fun(int i,int j=2,int k);  ✘

有預設引數值的引數必須在參數列的最右端

fun(10);//實際傳入10

fun (10,20);//實際傳入10,20,不是10,2

fun(10,20,30);//實際傳入10,20,30 

無實參則用預設值,否則實參覆蓋預設值

2、函式過載

在相同作用域內

實現同一函式可以傳入不同型別。

示例:

int getmax(int i,int j);

double getmax(double i,double j);

兩個過載函式必須在下列乙個或兩個方面有所區別:

1、函式的引數個數不同。

2、函式的引數型別不同或者引數型別順序不同,

c++的這種程式設計機制給程式設計者極大的方便,不需要為功能相似、引數不同的函式選用不同的函式名,也增強了程式的可讀性。

(1)不能改變運算子的優先順序;

(2)不能改變運算子的結合型;

(3)預設引數不能和過載的運算子一起使用;

(4)不能改變運算子的運算元的個數;

(5)不能建立新的運算子,只有已有運算子可以被過載;

(6)運算子作用於c++內部提供的資料型別時,原來含義保持不變。

3、內聯函式

編譯時將函式體**和實參代替函式呼叫語句

如:

在c++中我們通常定義以下函式來求兩個整數的最大值:

**如下:

int max(int a, int b)

為這麼乙個小的操作定義乙個函式的好處有:

① 閱讀和理解函式 max 的呼叫,要比讀一條等價的條件表示式並解釋它的含義要容易得多

② 如果需要做任何修改,修改函式要比找出並修改每一處等價表示式容易得多

③ 使用函式可以確保統一的行為,每個測試都保證以相同的方式實現

④ 函式可以重用,不必為其他應用程式重寫**

雖然有這麼多好處,但是寫成函式有乙個潛在的缺點:呼叫函式比求解等價表示式要慢得多。在大多數的機器上,呼叫函式都要做很多任務作:呼叫前要先儲存暫存器,並在返回時恢復,複製實參,程式還必須轉向乙個新位置執行

c++中支援內聯函式,其目的是為了提高函式的執行效率,用關鍵字 inline 放在函式定義(注意是定義而非宣告,下文繼續講到)的前面即可將函式指定為內聯函式,內聯函式通常就是將它在程式中的每個呼叫點上「內聯地」展開,假設我們將 max 定義為內聯函式:

**如下:

inline int max(int a, int b)

則呼叫: cout< b ? a : b)<將內聯函式放入標頭檔案

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

如下風格的函式 foo 不能成為內聯函式:

**如下:

inline void foo(int x, int y);   // inline 僅與函式宣告放在一起   

void foo(int x, int y)

而如下風格的函式 foo 則成為內聯函式:

**如下:

void foo(int x, int y);   

inline void foo(int x, int y)   // inline 與函式定義體放在一起

所以說,c++ inline函式是一種「用於實現的關鍵字」,而不是一種「用於宣告的關鍵字」。一般地,使用者可以閱讀函式的宣告,但是看不到函式的定義。儘管在大多數教科書中內聯函式的宣告、定義體前面都加了 inline 關鍵字,但我認為 inline 不應該出現在函式的宣告中。這個細節雖然不會影響函式的功能,但是體現了高質量c++/c 程式設計風格的乙個基本原則:宣告與定義不可混為一談,使用者沒有必要、也不應該知道函式是否需要內聯。

定義在類宣告之中的成員函式將自動地成為內聯函式,例如:

**如下:

class a

// 自動地成為內聯函式  

} 但是編譯器是否將它真正內聯則要看 foo函式如何定義

內聯函式應該在標頭檔案中定義,這一點不同於其他函式。編譯器在呼叫點內聯展開函式的**時,必須能夠找到 inline 函式的定義才能將呼叫函式替換為函式**,而對於在標頭檔案中僅有函式宣告是不夠的。

當然內聯函式定義也可以放在原始檔中,但此時只有定義的那個原始檔可以用它,而且必須為每個原始檔拷貝乙份定義(即每個原始檔裡的定義必須是完全相同的),當然即使是放在標頭檔案中,也是對每個定義做乙份拷貝,只不過是編譯器替你完成這種拷貝罷了。但相比於放在原始檔中,放在標頭檔案中既能夠確保呼叫函式是定義是相同的,又能夠保證在呼叫點能夠找到函式定義從而完成內聯(替換)。

但是你會很奇怪,重複定義那麼多次,不會產生鏈結錯誤?

我們來看乙個例子:

a.h :

**如下:

class a

int max();

private:

int a;

int b;

};a.cpp : 

**如下:

#include "a.h"

inline int a::max()

main.cpp : 

**如下:

#include

#include "a.h"

using namespace std;

inline int a::max()

int main()

{a a(3, 5);

cout《一切正常編譯,輸出結果:5

error lnk2001: unresolved external symbol "public: int __thiscall a::max(void)" (?max@a@@qaehxz)main.obj

找不到函式的定義,所以內聯函式可以在程式中定義不止一次,只要 inline 函式的定義在某個原始檔中只出現一次,而且在所有原始檔中,其定義必須是完全相同的就可以。

在標頭檔案中加入或修改 inline 函式時,使用了該標頭檔案的所有原始檔都必須重新編譯。

4.  慎用內聯

內聯雖有它的好處,但是也要慎用

而在google c++編碼規範中則規定得更加明確和詳細。

內聯函式:

tip: 只有當函式只有 10 行甚至更少時才將其定義為內聯函式.

定義: 當函式被宣告為內聯函式之後, 編譯器會將其內聯展開, 而不是按通常的函式呼叫機制進行呼叫.

優點: 當函式體比較小的時候, 內聯該函式可以令目標**更加高效. 對於訪問函式以及其它函式體比較短, 效能關鍵的函式, 鼓勵使用內聯.

缺點: 濫用內聯將導致程式變慢. 內聯可能使目標**量或增或減, 這取決於內聯函式的大小. 內聯非常短小的訪問函式通常會減少**大小, 但內聯乙個相當大的函式將戲劇性的增加**大小. 現代處理器由於更好的利用了指令快取, 小巧的**往往執行更快。

結論: 乙個較為合理的經驗準則是, 不要內聯超過 10 行的函式. 謹慎對待析構函式, 析構函式往往比其表面看起來要更長, 因為有隱含的成員和基類析構函式被呼叫!

另乙個實用的經驗準則: 內聯那些包含迴圈或 switch 語句的函式常常是得不償失 (除非在大多數情況下, 這些迴圈或 switch 語句從不被執行).

有些函式即使宣告為內聯的也不一定會被編譯器內聯, 這點很重要; 比如虛函式和遞迴函式就不會被正常內聯. 通常, 遞迴函式不應該宣告成內聯函式.(遞迴呼叫堆疊的展開並不像迴圈那麼簡單, 比如遞迴層數在編譯時可能是未知的, 大多數編譯器都不支援內聯遞迴函式). 虛函式內聯的主要原因則是想把它的函式體放在類定義內, 為了圖個方便, 抑或是當作文件描述其行為, 比如精短的訪問函式.

-inl.h檔案:

tip: 複雜的內聯函式的定義, 應放在字尾名為 -inl.h 的標頭檔案中.

內聯函式的定義必須放在標頭檔案中, 編譯器才能在呼叫點內聯展開定義. 然而, 實現**理論上應該放在 .cc 檔案中, 我們不希望 .h 檔案中有太多實現**, 除非在可讀性和效能上有明顯優勢.

如果內聯函式的定義比較短小, 邏輯比較簡單, 實現**放在 .h 檔案裡沒有任何問題. 比如, 訪問函式的實現理所當然都應該放在類定義內. 出於編寫者和呼叫者的方便, 較複雜的內聯函式也可以放到 .h 檔案中, 如果你覺得這樣會使標頭檔案顯得笨重, 也可以把它萃取到單獨的 -inl.h 中. 這樣把實現和類定義分離開來, 當需要時包含對應的 -inl.h 即可。

c 函式特性

1.內斂函式在函式的宣告和定義前面都要加上關鍵字 inline 2.內聯函式是c 為提高程式執行速度所做的一項改進,與常規函式區別在於c 編譯器如何將它組合到程式中,所謂的的 內聯 是編譯器將使用相應的函式 來替換函式呼叫,程式無需跳轉到另乙個位置執行 再跳回來。所以速度比常規函式稍快,但是代價是需...

C 函式特性

1.函式引數預設值 比較兩個函式預設值的正確性 void fun int i,int j 5,int k 10 正確 void fun int i,int j 5,int k 錯誤 有函式引數值的引數必須在引數列表的最右端!2.使用時的一些注意事項 為了避免某些編譯器不通過,建議在宣告時給函式加預設...

C函式引數特性

編寫日期 2012.5.22 前言 c語言,是函式構成的語言,c離不開函式,函式對於c的存在有著決定性的作用。那麼,函式引數對於c的重要性也就可想而知了。下面我就談談c函式引數的一些性質。引數特性簡介 特點一 函式引數的傳遞順序。例項一 void func int id1 int id2 void ...