坑!c++
int f(i++,i) //默認是不清楚先計算i仍是i++的,沒有規定實參的求值順序,可是,能夠假設從後往前計算,c語言中是這個過程 int f(int a,int) //形參名是可選的,通常狀況下須要一個名字,不提供也行,就是找不到這個形參 int f() {
static int a=0;
//這個局部靜態對象的生命週期是一直到整個進程結束!進程!
//未顯式初始化則默認初始化爲0(內置類型)
}
int f(int ,int);
//聲明裏面不必定須要形參名,注意是聲明!
//函數三要素:返回類型(不寫其實默認爲int),函數名,形參類型
int f(int &a,int &b) //傳引用,可修改 //可是不能夠傳一個字面值,好比f(1,2),引用類型不能夠初始化爲字面值 int f(const int &a,const int &b) //這就能夠了。。。。f(1,2)沒有問題 //使用引用能夠避免拷貝,特別大的字符串的時候! //傳遞數組的時候,實際上傳遞的是數組的指針 //多維數組就不說了 //若是有問題,想一想這樣初始化這個形參是否會出現問題 複製代碼
若是不清楚形參的數量,可使用省略符形參數組
void foo(int a,...) void foo(...) 複製代碼
在含有return語句的循環後面應該也有一條return語句,若是沒有的話就是錯誤的,若是編譯器沒有發現這個錯誤,則運行時的行爲就是未定義的。函數
for(int i=0;i<n;i++)
if(i>8)
return;
return; //必須寫以防止最後不返回
複製代碼
不要返回局部對象的引用或者指針,局部變量使用的空間在函數結束後是會被釋放的,因此不能夠返回局部變量的指針或者引用。可是返回局部變量的值是能夠的,由於使用的是拷貝的數據。ui
const string &manip() {
string ret;
if(!ret.empty())
return ret; //錯誤,返回局部變量的引用
else
return "abv"; //錯誤,這是一個局部臨時量,在函數結束的時候同樣會被清空空間
}
複製代碼
返回類類型或者引用,指針之類的函數,可使用函數調用的結果訪問其成員spa
auto z=shorterString(s1,s2).size();
//返回一個引用類型的函數能夠當作左值
char &get_val(string &s,int x) {return s[x];}
int main() {
get_val(s,x)=1; //直接當作左值修改
}
複製代碼
也可使用列表初始化返回指針
return {1,2,3} //通常用來返回容器類型
複製代碼
若是同一做用域內的幾個函數名字相同可是形參列表不一樣(形參數量或形參類型),則稱之爲重載函數。code
注意:main函數是不能重載的對象
int fun(int a,int b);
int fun(int a) int fun(char c) int fun(int c) //這就不是重載 int fun(int) //這也不是重載 複製代碼
注意,函數參數是不承認頂層const的,因此默認頂層const加不加都同樣。生命週期
int fun(int a);
int fun(const int a); //不能夠,頂層const
int fun(int *a);
int fun(int * const a); //不能夠,頂層const
//若是形參是某種類型的指針或者引用,則經過區分其指向的是常量對象仍是很是量對象能夠實現函數重載,此時const是底層的
int fun(int &);
int fun(const int &); //能夠重載,底層const
int fun(int *);
int fun(const int *); //能夠重載,底層const
複製代碼
注意須要避免函數重載的二義性!進程
在不一樣的做用域中沒法重載函數!
能夠爲函數形參賦值默認實參(在聲明中賦值)
int fun(int a,int b,int c=1);
//能夠爲一個或者多個形參賦值默認值,可是,一旦一個形參賦值了,則後面的形參都必須有默認實參
int fun(int a,int b=1,int c); //沒法分辨fun(1,2)的二義性
//注意沒法修改一個已經存在的默認值
int fun(int ,int ,int c=2); //錯誤
//可是能夠添加默認實參
int fun(int a,int b=2,int c=1); //正確
##函數調用時實參按其位置解析,默認實參負責填補函數調用缺乏的尾部實參
int fun(string a="123",int a=1,int b=2);
fun(,2,3); //錯誤,默認補充尾部默認參數,想修改哪一個那前面的都不能跳過!
//只能忽略尾部的實參
fun("1",2+1); //假如想修改b這個程序會和預期不符,因此要消除二義性
複製代碼
內聯函數,能夠避免函數調用的開銷,不會進入到函數的地址區,而是經過編譯器直接將函數代碼"粘貼"到對應位置,因此不適用於大型的函數,只適用於小型的,頻繁調用的函數。
inline int f(int a,int b) {return a>b?a:b;}
cout<<f(1,2)<<endl;
//等價於
cout<<1>2?1:2<<endl;
複製代碼
assert預處理宏
assert(expr)
//表達式爲假則輸出信息並終止程序的運行
//爲真則什麼也不作
複製代碼
具體操做以下
void f();
void f(int);
void f(int,int);
void f(double,double=3.14);
f(5.6);
(1)肯定候選函數
1.與被調用的函數重名
2.其聲明在調用點可見
//無淘汰
(2)肯定可行函數
1.形參數量與本次調用提供的實參數量相等(考慮默認參數但是可行的)
2.每一個參數的類型與對應的形參類型相同,或者能轉換成形參類型
//淘汰第1,3
//若是這步未找到可行函數,編譯器會報無匹配函數錯誤
(3)尋找最佳匹配
尋找形參類型與實參類型最匹配的那個函數
最佳匹配等級:
1.精確匹配
實參類型和形參類型相同
實參從數組類型或函數類型轉換成對應的指針類型
向實參添加頂層const或者從實參中刪除頂層const
2.經過const轉換實現匹配(底層const)
3.經過類型提高實現的匹配
4.經過算術類型轉換或指針轉換實現的匹配
5.經過類類型轉換實現的匹配
(若是重載函數的區別只是多了個底層const的話,將從函數調用的實際參數類型(常量或者很是量)來判斷)
多個形參的函數匹配
1.該函數每一個實參的匹配都不劣於其餘可行函數須要的匹配
2.至少有一個實參的匹配優於其餘可行函數提供的匹配
若是檢查了以後沒有找到惟一的一個函數脫穎而出,則編譯器報告二義性調用的信息。
//f(42,2.56)
//典型的二義性錯誤
複製代碼
函數指針指向的是函數不是對象。
int max(int a,int b);
//聲明一個能夠指向該函數的指針,只須要用指針替換函數名便可
int (*p)(int ,int);
//將函數賦值給函數指針的時候能夠忽略取地址符
p=max;
p=&max; //加不加都同樣
//調用函數指針指向的函數的時候用不用解引用指針也同樣
cout<<p(1,2)<<endl;
cout<<(*p)(1,2)<<endl;
//能夠爲函數指針賦值0或者nullptr表示沒有指向任何位置
//當使用重載函數的時候,上下文必須清晰的界定到底使用的是哪一個函數,不能夠一對多
複製代碼