一、內聯函數
1、C++中的const常量可以替代宏常數定義,如:
const int A = 3; #define A 3
C++中是否有解決方案替代宏代碼片段呢?(替代宏代碼片段就可以避免宏的副作用!)
2、C++中推薦使用內聯函數替代宏代碼片段
C++中使用inline關鍵字聲明內聯函數
內聯函數聲明時inline關鍵字必須和函數定義結合在一起,否則編譯器會直接忽略內聯請求。
#includeusing namespacestd; #define MIN(a,b) ((a) < (b) ? (a) : (b)) inline int myfunc(inta, int b) { return a < b ? a : b; } int main(void) { int a = 1; int b = 3; //int c = myfunc(++a, b); int c = MIN(++a, b); printf("a = %d\n", a); printf("b = %d\n", b); printf("c = %d\n", c); return 0; }
說明1:必須inline intmyfunc(int a,int b)和實現的地方,寫在一塊。
說明2:C++編譯器可以將一個函數進行內聯編譯;被C++編譯器內聯編譯的函數叫做內聯函數;內聯函數在最終生成的代碼中是沒有定義的;C++編譯器直接將函數體插入函數調用的地方;內聯函數沒有普通函數調用時的額外開銷(壓棧,跳轉,返回)。
說明3:C++編譯器不一定准許函數的內聯請求
說明4:內聯函數是一種特殊的函數,具有普通函數的特征(參數檢查,返回類型等);內聯函數是對編譯器的一種請求,因此編譯器可能拒絕這種請求;內聯函數由編譯器處理,直接將編譯後的函數體插入調用的地方;宏代碼片段由預處理器處理,進行簡單的文本替換,沒有任何編譯過程。
說明5:現代C++編譯器能夠進行編譯優化,因此一些函數即使沒有inline聲明,也可能被編譯器內聯編譯;另外,一些現代C++編譯器提供了擴展語法,能夠對函數進行強制內聯,如:g++中的__attribute__((always_inline))屬性。
說明6:
C++中內聯編譯的限制:
不能存在任何形式的循環語句;不能存在過多的條件判斷語句;函數體不能過於龐大;不能對函數進行取址操作;函數內聯聲明必須在調用語句之前。
結論:
(1)內聯函數在編譯時直接將函數體插入函數調用的地方
(2)inline只是一種請求,編譯器不一定允許這種請求
(3)內聯函數省去了普通函數調用時壓棧,跳轉和返回的開銷
二、默認參數
1、C++中可以在函數聲明時為參數提供一個默認值, 當函數調用時沒有指定這個參數的值,編譯器會自動用默認值代替。
2、只有參數列表後面部分的參數才可以提供默認參數值,一旦在一個函數調用中開始使用默認參數值,那麼這個參數後的所有參數都必須使用默認參數值。
三、函數占位參數
占位參數只有參數類型聲明,而沒有參數名聲明;一般情況下,在函數體內部無法使用占位參數。
四、函數重載
用同一個函數名定義不同的函數;當函數名和不同的參數搭配時函數的含義不同。
int func(int x) { return x; } int func(int a, int b) { return a + b; } int func(const char *s) { return strlen(s); } int main(intargc, char *argv[]) { int c = 0; c = func(1); printf("c = %d\n", c); c = func(1, 2); printf("c = %d\n", c); c = func("12345"); printf("c = %d\n", c); return 0; }
函數重載至少滿足下面的一個條件:
參數個數不同
參數類型不同
參數順序不同
編譯器調用重載函數的准則
將所有同名函數作為候選者
嘗試尋找可行的候選函數
精確匹配實參
通過默認參數能夠匹配實參
通過默認類型轉換匹配實參
匹配失敗
最終尋找到的可行候選函數不唯一,則出現二義性,編譯失敗。
無法匹配所有候選者,函數未定義,編譯失敗。
函數重載的注意事項
重載函數在本質上是相互獨立的不同函數(靜態鏈編)
重載函數的函數類型是不同的
函數返回值不能作為函數重載的依據
函數重載是由函數名和參數列表決定的。
函數重載與函數指針
當使用重載函數名對函數指針進行賦值時
根據重載規則挑選與函數指針參數列表一致的候選者
嚴格匹配候選者的函數類型與函數指針的函數類型