一,異常的推演
1.函數與異常
平時我們在函數中出現異常情況時通常通過return終止函數並返回一個值,然后在函數上層來獲取值並判斷是什么異常情況。因為函數是棧結構的,所以return的時候是通過棧結構逐步往上的,不能夠跨函數直接拋出,不方便。所以C++推出了異常機制,通過異常機制我們可以輕松的捕獲要出現的異常。
2.C++中異常的基本演示
# include<iostream> using namespace std; /* 定義求商函數,如果除數為0,拋出double類型異常 */ double div(double d1, double d2) { if (d2 == 0) { throw d2; } return d1 / d2; } int main() { /* try...catch語句來捕獲異常 */ try { double result = div(1.02, 0.0); } catch (double e) { /* C++中的異常嚴格要求類型匹配,即拋出什么的異常就catch什么類型的異常 */ cout << e << "不能作除數" << endl; } catch (...) { cout << "未知異常" << endl; } return 0; }
3.C++中異常的總結
- 異常的捕捉嚴格匹配數據類型,不支持類型自動轉換,throw的是int類型則catch的必須是int類型否則不會匹配。
- 一般我們在異常最后加入catch(...)這樣能夠捕獲任意異常。
二,自定義異常類
1.異常類
按照面向對象的思維,我們的異常也應該是一個對象,所以在拋出異常的時候,我們通常自定義一個異常類,然后把異常信息放入異常類中,然后在捕捉到異常對象的時候,再調用對象的方法,打印出異常的信息。
2.異常類代碼演示
# define _CRT_SECURE_NO_WARNINGS # include<iostream> using namespace std; /* 自定義異常類 */ class MyException { private: char * content; public: /* 異常類構造函數 */ MyException(const char * content) { this->content = new char[strlen(content) + 1]; strcpy(this->content, content); cout << "異常類有參構造函數執行" << endl; } /* 異常類拷貝構造函數 */ MyException(const MyException& me) { this->content = new char[strlen(me.content) + 1]; strcpy(this->content, me.content); cout << "異常類拷貝構造函數執行" << endl; } /* 異常類析構函數 */ ~MyException() { if (this->content != NULL) { delete[] this->content; this->content = NULL; } cout << "異常類的析構函數執行" << endl; } /* 異常類拋出異常信息 */ void toString() { cout << this->content << endl; } }; /* 定義測試異常的函數 */ double divide(double d1, double d2) { if (d2 == 0) { throw MyException("除數不能為0"); //throw new MyException("除數不能為0"); } return d1 / d2; } int main() { try { double result = divide(1, 0); cout << "result = " << result << endl; } catch (MyException e) { // catch的異常是元素類型,執行的是拷貝構造函數,存在兩個異常對象,釋放兩個異常對象,不合理 e.toString(); } catch (MyException * e) { // catch的異常是指針類型,必須我們手動調用delete方法才能調用析構函數,不合理 e->toString(); delete e; } catch (MyException& e) { // catch的是引用類型,是原先拋出的對象,會自動執行析構函數,我們使用引用來接收拋出的異常對象 e.toString(); } catch (...) { cout << "未知異常" << endl; } return 0; }
3.自定義異常類總結
- 拋出異常對象通常用引用的方式來catch這個對象,如果是元素catch異常對象則會執行拷貝構造函數,創建兩個重復異常對象並釋放兩次對象,所以說不合理。如果catch的是指針類型,不會自動調用該對象的析構函數必須我們手動delete,也不符合自動調用的邏輯,所以使用引用的方式來catch異常對象。
三,標准異常類
1.標准異常類
C++中提供了標准的異常類,需要# include<exception>,標准異常類為exception,該類有個what函數,可以打印異常對象的異常信息。該what函數是虛函數,我們需要繼承exception類並重寫該what函數,在捕捉異常的時候,我們用父類的引用來接收自定義的標准異常類的子類對象(類型兼容性原則),然后打印該異常信息即可。
2.標准異常類演示
# include<iostream> # include<exception> using namespace std; /* 繼承自標准異常類 */ class DivException :public exception { private: const char * ptr; public: /* 構造函數接收異常信息 */ DivException(const char * ptr) { this->ptr = ptr; } /* 重寫what函數 */ virtual char const * what() const { cout << this->ptr << endl; return ptr; } }; /* 測試異常函數 */ int divi(int a, int b) { if (b == 0) { throw DivException("除數不能為0"); } return a / b; } int main() { try { divi(10, 0); } catch (exception& e) { /* 使用exception引用接收自定義的子類對象 */ e.what(); } catch (...) { cout << "未知異常" << endl; } return 0; }