異常處理
需要人爲throw才能catch,與Java的機制有所區別
throw拋出的異常可以是任意類型
#include <stdexcept> /* * …… */ int num[10] = {0}; try { num[0] = num [1]; throw num[0]; } catch(int err) { cout << "error happend" << endl; } try { throw runtime_error("this is a run time error"); } catch(runtime_error err) { cout << err.what() << endl; }
函數基礎
局部靜態變量
在程序的執行路徑第一次經過對象定義語句時初始化,直到程序終止時才銷燬。
int call_count() { static int count = 0; return ++count; } int main() { for(int i = 0; i < 5; i++) { call_count(); } cout << call_count() << endl; //the output is 6 }
使用引用參數傳遞省去拷貝
const參數
void fun(const int num); //num只能讀不能寫
可變形參的函數
類型相同,數量不同
void init_list_test(initializer_list<string> str) { for(auto it = str.begin(); it != str.end; it++) cout << *it << " "; cout << endl; } init_list_test({"this", "is", "a", "test"});
省略符形參
#include <stdarg.h> using namespace std; void argFun(int parNum, ...) { va_list ap; char* s; va_start(ap, parNum); for(int i = 0; i < parNum; i++) { s = va_arg(ap, char*); cout << s << endl; } } int main() { argFun(3, "hello", "world", "!"); }
也可以只有省略號,完全忽略形參
尾置返回類型
用於返回類型比較複雜的情況,特別是沒有左值的類型
auto fun(int i) -> int (*)[10] //等價於int (*fun(int i))[10] { static int num[10]; for(int j = 0; j < 10; j++) { num[j] = i + j; } return # } int main() { void *result; result = fun(-5); int *temp; for(int i = 0; i < 10; i++) cout << *(temp = (((int*) result) + i)) << endl;
使用decltype,如下函數定義與上述方法等價
int type[10] = {0}; decltype(type) *fun(int i)
函數重載
同一作用域內的幾個函數名字相同但形參列表不同,返回值也可以不同
int func(int *ptr); int func(int* const prt); //重複聲明瞭前者 int func(const int *prt); //新函數,作用域指向常量的指針 int func_new(int &num); int func_new(const int &num); //新函數,作用域常量引用
有無頂層const無法被區分,有無底層const可以被區
非常量可以轉化爲常量,所以比如當僅有3時,傳遞一個非常量的prt沒有錯誤,但若同時存在1,3,則編譯器會優先選擇1
const_cast強制轉換與重載
如下函數,即省去了函數返回值拷貝的過程,又解決了實參不是const類型時的麻煩
const int &func(const int &i, const int &j); int &func(int &i, int &j); int main() { int m = 1, n = 3; int &result = m; result = func(m ,n); cout << result << endl; } const int &func(const int &i, const int &j) { return (i > j) ? i : j; } int &func(int &i, int &j) { const int &temp = func(const_cast<const int&>(i), const_cast<const int&>(j)); return const_cast<int&>(temp); }
const_cast還可用於多線程下volatile關鍵字
避免二義性調用
當有多個函數可以匹配時
默認實參
int caculateSquare(int width = 10, int length = 10);
調用時只能省去尾部的實參
內聯函數
直接替換,省去開銷,一般較小,不支持遞歸
inline int getMax(int i, int j);
內聯函數必須是和函數體申明在一起,纔有效。
內聯函數和宏很類似,而區別在於,宏是由預處理器對宏進行替代,不檢查函數參數,返回值,而內聯函數是通過編譯器控制來實現的。而且內聯函數是真正的函數,只是在需要用到的時候,內聯函數像宏一樣的展開,所以取消了函數的參數壓棧,減少了調用的開銷。你可以象調用函數一樣來調用內聯函數,而不必擔心會產生於處理宏的一些問題。
constexpr
用於常量表達式的函數
返回值及所有形參類型比學位字面值類型,函數體中必須只有一條return語句
可以返回非常量,編譯器檢查上下文
通常放在頭文件中
調試幫助:assert與NDEBUG
assert是一種預處理宏,包含在頭文件assert.h中
assert(expr); expr爲假時,打印錯誤,退出;expr爲真時,doing nothing
assert的缺點是極大影響程序的性能,產生額外開銷
調試結束後可以在#include<assert.h>前加入#define NDEBUG來使所有assert失效
可以利用NDEBUG編寫自己的調試代碼
#ifndef NDEBUG cerr << "error:NDEBUG test success" ; #endif
預處理器還提供了幾個對於調試很有用的局部靜態變量
__func__ 當前調試的函數名
__FILE__ 存放當前文件名
__LINE__ 當前行號
__TIME__ 文件編譯時間
__DATE__ 文件編譯日期
函數指針
聲明一個函數指針
bool (*prtf)(double x, int n); //未初始化
可以直接給prtf賦值
int sum(int x, int y) { return x + y; } prtf1 = sum; prtf2 = ∑//等價 prtf1(1,2); (*prtf)(1,2); //等價
重載函數也可以有函數指針
函數指針可以作爲形參傳入
int prtfPara(int x, int y, int (*prtf) (int m, int n)) { return prtf(x, y) + x; } cout << prtfPara(1, 2, sum) <<endl;
可以用typedef和decltype定義函數的類型,避免冗長和繁瑣
typedef int functype1(int x, int y); typedef decltype(sum) *functype2; int prtfPara(int x, int y, functype2 prtf)
返回函數指針的函數
typedef int(*PF)(int x, int y) ; PF pf1(int x) { return sum; } functype1 *func1 = pf1(1); cout << func1(4, 5) << endl;
也可這樣聲明func1
int (*func2(int m))(int x, int y);
注意:當decltype作用於某個函數時,它返回函數類型而不是指針類型,需要顯式的加上*表明是指針類型,例如functype2
最近開的書比較多,上週末又病了一場,節奏有點不太對,有待調整!