Chap 17 異常處理 目之與形,吾不知其異也,而盲者不能自見, 耳之與形,吾不知其異也,而聾者不能自聞; 心之與形,吾不知其異也,而狂者不能自得。 形之與形亦辟矣,而物或間之邪? 《莊子﹒雜篇 卷八上第二十三庚桑楚》 一個完整的程式即使遇到了異常狀況,也要可以正常結束。

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

第一單元 建立java 程式.
計算機程式語言實習課.
第 2 章 初探 C++.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
Data Abstraction: The Walls
File Access 井民全製作.
第八章 类和对象.
C++程序设计 王希 图书馆三楼办公室.
程式設計概論 1.1 程式設計概論 程式語言的演進 物件導向程式 程式開發流程 1.2 C++開發工具
struct 可以在同一個名稱下擁有多種資料型態。使用struct能讓資料的存取和處理更為靈活。
簡易C++除錯技巧 長庚大學機械系
資料大樓 --談指標與陣列 綠園.
函數(一) 自訂函數、遞迴函數 綠園.
資料結構設計與C++程式應用 Fundamentals of Data Structures and Their Applications Using C++ 第3章 佇列 資料結構設計與C++程式應用.
Chap 18 類別與物件 夫有土者,有大物也。有大物者,不可以物。 物而不物,故能物物。 明乎物物者之非物也,豈獨治天下百姓而已哉!
Scope & Lifetime 前言 Local Scope Global Functions & Objects
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
第一章 程序的基本结构. 第一章 程序的基本结构 教材及授课结构 本章目标 基本内容 扩展阅读 上机指导 应用举例 习题.
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
前處理指令可以要求前處理器 (preprocessor) 在程式編譯之前,先進行加入其它檔案的內容、文字取代以及選擇性編譯等工作。
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
類別(class) 類別class與物件object.
SQL Stored Procedure SQL 預存程序.
C++程序设计 string(字符串类) vector(容器类).
Java 程式設計 講師:FrankLin.
service-side: throw Exceptions client-side: try-and-catch
程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
第一單元 建立java 程式.
C++ 程式設計 基礎篇 張啟中 Chang Chi-Chung.
開始使用Visual C++.
第 19 章 XML記憶體執行模式.
常宝宝 北京大学计算机科学与技术系 数据结构(三) 常宝宝 北京大学计算机科学与技术系
C++大学基础教程 第11章 多态性 北京科技大学 信息基础科学系 2019/4/8 北京科技大学.
Name1..hour //加班時數 name2..hour //請假時數
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
第十二章 命名空间和异常处理 丘志杰 电子科技大学 计算机学院 软件学院.
挑戰C++程式語言 ──第8章 進一步談字元與字串
Oop8 function函式.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
物件導向程式設計 CH2.
C++ 與 物件導向 程式設計概念簡介 魏天君 2019/5/3.
C++程式設計入門 變數與運算子 作者:黃建庭.
挑戰C++程式語言 ──第7章 輸入與輸出.
流程控制:Switch-Case 94學年度第一學期‧資訊教育 東海大學物理系.
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
#include <iostream.h>
物件導向程式設計 參考書目: 1. 洪維恩,C++ 教學手冊 第三版,旗標出版圖書公司。 2. 陳錦揮,Java 初學指引,博碩文化 3
選擇性結構 if-else… switch-case 重複性結構 while… do-while… for…
C++语言程序设计 第十章 C++标准模板库 成都信息工程学院计算机系.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
Chap 6 函數 故用兵之法,十則圍之,五則攻之,倍則分之, 敵則能戰之,少則能逃之,不若則能避之。 故小敵之堅,大敵之擒也。
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
String類別 在C語言中提供兩種支援字串的方式 可以使用傳統以null結尾的字元陣列 使用string類別
變數與資料型態  綠園.
Array(陣列) Anny
C語言程式設計 老師:謝孟諺 助教:楊斯竣.
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
方法(Method) 函數.
InputStreamReader Console Scanner
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

Chap 17 異常處理 目之與形,吾不知其異也,而盲者不能自見, 耳之與形,吾不知其異也,而聾者不能自聞; 心之與形,吾不知其異也,而狂者不能自得。 形之與形亦辟矣,而物或間之邪? 《莊子﹒雜篇 卷八上第二十三庚桑楚》 一個完整的程式即使遇到了異常狀況,也要可以正常結束。

Chap 17 異常處理 17.1 異常及其特性 17.2 異常處理的基本語法 17.3 異常的處理過程 17.4 丟擲enum實例做為異常物件 17.5 丟擲類別所定義的物件

17.1 異常 (exceptions) 異常指的是所有可以造成電腦無法正常處理的狀 況。 經常遇到的異常狀況可以分為五種: 1. 資源不足: 又分為「記憶體不足」 (out of memory) 和「儲存空間耗盡」兩種情況。 2. 開檔失敗: 又分為「讀檔」和「存檔」兩種情況。 3. 越界: 索引超過上限或低於下限。 4. 除數為零: 在進行數值除法運算時,經常造成當機。 5. 使用者輸入錯誤

異常的幾個特性 1. 發生時,電腦無法正常地繼續執行工作。 2. 在程式寫作時,無法預知何時會發生。 3. 無法避免,但是可以預先做好因應對策。

當異常發生的可能結果 1. 無預警地突然結束或當機。 2. 程式自動結束,但沒有任何相關訊息。 3. 發出警告訊息後程式自行正常結束。 4. 自行跳過異常部份,但其後的運算可能沒有意義。 5. 通知使用者異常發生的種類,並引導使用者逐步排除異常後繼續工作。

17.2 異常處理的基本語法 C++ 提供了try (嚐試),throw (丟擲),和 catch (捕捉) 三個關鍵字。 把所有可能發生異常的敘述都放在「try區 塊」(try block)。

throw敘述 (throw statement) 和catch區塊 在所有可能發生異常的敘述之前,都可以使 用「throw敘述」丟擲出一個異常訊息物件 (the exception message object)。 通常「throw敘述」都不直接在「try區塊」 之內,而是在「try區塊所呼叫的函數」內。 「catch區塊」用來承接由相關「throw敘 述」所丟出來的訊息物件。

實例: 以「異常處理」的方式阻止程式進行除以零的運算。 我們將程式區分為Exception.cpp和FncLib.cpp兩 個檔案: 1. 檔案Exception.cpp為主程式,包括呼叫函數Divide() 的「try 區塊」,以及準備接收訊息物件的「catch 區塊」。 2. 檔案FncLib.cpp包括的是函數Divide() 的定義。當異常 (除數為零) 發生時,執行「throw敘述」以丟擲出字串訊息物件: throw "除數為零!";

範例程式 檔案 Exception.cpp // Exception.cpp #include <iostream> using namespace std; // --- 函數 Divide() 的原型 ---------------------- float Divide(float, float); // --------- 主程式 ----------------------------- int main() { float M, N; try // 「try 區塊」的開頭 cout << "請輸入兩個數字,\n" << endl; cout << "請輸入第一個數字 :" << endl;

cin >> M; cout << "請輸入第二個數字 :" << endl; cin >> N; cout << "您輸入了 : " << M << " 和 " << N << endl; cout << "這兩個數字相除的結果是: " << Divide(M,N) << endl; } // 「try 區塊」的結尾 catch (char* pError) // 「catch 區塊」的開頭 { cerr << "發生異常: " << pError << endl; } // 「catch 區塊」的結尾 return 0; }

範例程式 檔案 FncLib.cpp // FncLib.cpp #include <cmath> using std::fabs; const float Epsilon = 1.0E-16; // --- 定義函數 Divide() ---------------------------- float Divide(float a, float b) { if (fabs(b) <= Epsilon) throw "除數為零!"; // 「throw 敘述」 return a / b; }

操作結果 兩個典型操作過程的記錄: 操作1 操作2 請輸入兩個數字, 請輸入第一個數字: 23.5 請輸入第二個數字: 7.92 您輸入了 : 23.5 和 7.92 這兩個數字相除的結果是: 2.96717 656.3 您輸入了 : 656.3 和 0 發生異常: 除數為零!

堆疊 (stack) 加入、移出的動作遵守「後進先出」的原 則,就好像我們堆積碗盤的過程,因此稱 為堆疊。

呼叫堆疊(call stack)因為函數閒互相呼叫而發生的變化 假設Fnc0() 內的敘述呼叫了Fnc1(),而Fnc1() 內 的敘述又呼叫了Fnc2(),則形成的堆疊(stack)就 會是:

17.3 異常的處理過程

執行throw敘述 它所在的函數立即執行return的動作,並同時叫 用解構函數 (destructor)。 如果在返回後的函數中找不到吻合的「catch區 塊」,將持續展開堆疊(unwinding the stack)。 如果找不到相吻合的「catch區塊」,就會被預 設的處理函數攔截,並在發出以下的訊息後立即 自動結束程式: Some exceptions happened.

捕捉所有遺漏異常物件的「catch區塊」 異常物件之區塊 (catch-all block),語法如下: catch (...) { // 捕捉之後的動作敘述放在這裏 } 其中三個點「...」代表「所有可能」的意思。

17.4 丟擲enum實例做為異常物件 例如: 宣告enum資料型態ErrorStates: enum ErrorStates {OK, OverFlow, UnderFlow};  定義一個ErrorStates實例,稱為State並初始化為OK: ErrorStates State = OK;

在異常發生前改變State的值並將其擲出 例如: State = OverFlow; throw State;

在「catch區塊」前,宣告與enum資料型態吻 合的實例 catch (ErrorStates Error) { // 捕捉之後的敘述 }

使用enum的異常處理範例 在每一次有可能超過陣列元素索引的上下限前,以 「異常處理」的方式阻止程式繼續運算。 程式區分為EnumEx.cpp和EnumFncLib.cpp兩個檔案: 1. 檔案EnumEx.cpp為主程式,包括呼叫函數ShowVectorElement() 的「try區塊」,以及準備接收訊息物件的「catch區塊」。 檔案EnumFncLib.cpp包括函數ShowVectorElement( ) 的定義。當異常(除數為零)發生時,執行「throw敘述」。

範例程式 檔案 EnumEx.cpp // EnumEx.cpp #include <iostream> using namespace std; float ShowVectorElement(float [],int); // 函數的原型 // 定義 enum資料型態ErrorStates enum ErrorStates {OK, OverFlow, UnderFlow}; // ---- 主程式 ----------------------- int main() { const int Size = 5; float V[Size]; int M; for (int i=0; i< Size; i++) V[i] = float(0.5+ i*i)/2.5;

try // 「try 區塊」的開頭 { cout << "請輸入一個數字(在 0 至 " << Size << " 範圍內):" << endl; cin >> M; cout << "您輸入了: " << M << endl; cout << "V[" << M << "]" << " 的值是: " << ShowVectorElement(V, M) << endl; } // 「try 區塊」的結尾

catch (ErrorStates Error) // 「catch 區塊」的開頭 { if (Error==OverFlow) cerr << "發生異常: OverFlow" << endl; if (Error==UnderFlow) cerr << "發生異常: UnderFlow" << endl; } // 「catch 區塊」的結尾 catch (...) // catch-all 區塊的開頭 {cerr << "發生了預計範圍之外的異常!" << endl; } // catch-all 區塊的結尾 return 0; }

範例程式 檔案 EnumFncLib.cpp // EnumFncLib.cpp #include <cmath> using std::fabs; // 定義 enum資料型態ErrorStates enum ErrorStates {OK, OverFlow, UnderFlow}; const float Epsilon = 1.0E-16; extern const int Size = 5;

// 函數 ShowVectorElement() 的定義 float ShowVectorElement(float A[],int N) { ErrorStates State = OK; // 定義enum實例 State if (N >= Size) State = OverFlow; throw State; // 「throw 敘述」 } if (N < 0) State = UnderFlow; throw State; // 「throw 敘述」 return A[N];

操作結果 三個典型操作過程的記錄: 操作 1 操作2 操作3 請輸入一個數字 (在 0 至 5 範圍內): 3 您輸入了: 3 V[3] 的值是: 3.8 5 您輸入了: 5 發生異常: OverFlow -2 您輸入了 : -2 發生異常: UnderFlow

17.5 丟擲類別 (Class) 所定義的物件(Object) class OverFlow{ }; // 不需要有具體內容 class UnderFlow{ }; 在異常發生處,其「throw敘述」可以直接寫成: throw OverFlow(); // ( ) 表示在執行 //「throw敘述」時 throw UnderFlow(); // 同時呼叫建構函數 //(constructor)

接收物件的「catch區塊」 例如: catch (OverFlow) // 接收端只要寫出類別名稱 { } catch (UnderFlow) // 捕捉UnderFlow物件之後的敘述

使用物件的異常處理範例 程式區分為Common.h,ObjEx.cpp和ObjFncLib.cpp三個檔 案: 1. 檔案Common.h為標頭檔,包括共同需要的名稱空間和函數的原型。 名稱空間ExcNameSpace定義了常數Size和Epsilon,以及OverFlow和UnderFlow兩種類別。 2. 檔案ObjEx.cpp為主程式,包括「try區塊」,以及準備接收訊息物件的「catch區塊」。 3. 檔案ObjFncLib.cpp內有函數的定義。 當異常 (除數為零) 發生時,執行「throw敘述」以丟擲出OverFlow或UnderFlow兩種類別產生的物件 (object)。

範例程式 檔案 Common.h //Common.h #ifndef COMMON_H #define COMMON_H #include <iostream> #include <iomanip> #include <math> using namespace std;

namespace ExcNameSpace { class OverFlow { }; class UnderFlow { }; const int Size = 5; const float Epsilon = 1.0E-16; } // - 函數 ShowVectorElement() 的原型 float ShowVectorElement(float [],int); #endif

範例程式 檔案 ObjEx.cpp // ObjEx.cpp #include "Common.h" using namespace ExcNameSpace; // ----主程式----------------------- int main() { const int Size = 5; float V[Size]; int M; for (int i=0; i< Size; i++) V[i] = float(0.5+ i*i)/2.5;

try // 「try 區塊」的開頭 { cout << "請輸入一個數字(在 0 至 " << Size << " 範圍內):" << endl; cin >> M; cout << "您輸入了: “ << M << endl; cout << "V[" << M << "]" << " 的值是: " << ShowVectorElement(V, M) << endl; } // 「try 區塊」的結尾 catch (OverFlow) cerr << "發生異常: OverFlow" << endl; }

catch (UnderFlow) { cerr << "發生異常: UnderFlow" << endl; } catch (...) cerr << "發生了預計範圍之外的異常!" << endl; return 0;

範例程式 檔案 ObjFncLib.cpp // ObjFncLib.cpp #include "Common.h" using namespace ExcNameSpace; // 函數 ShowVectorElement() 的定義 float ShowVectorElement(float A[],int N) { if (N>=Size) { throw OverFlow(); } // 「throw 敘述」 if (N < 0) { throw UnderFlow(); } // 「throw 敘述」 return A[N]; }

操作結果 程式的操作方式及功能都和17.4節相同。以下是三個典型操作過程的記錄: 操作 1 操作 2 操作 3 請輸入一個數字 (在 0 至 5 範圍內): 4 您輸入了: 4 V[4] 的值是: 6.6 6 您輸入了: 6 發生異常: OverFlow -1 您輸入了 : -1 發生異常: UnderFlow

「catch區塊」的編排次序 「特例」異常放在前面,「通例」異常放在後面。 例如: 絕大部分丟擲物件的語法都可以被丟擲字串的語法 所取代。 catch (Zero) { //捕捉Zero之後的敘述 } catch (TooSmall) { //捕捉TooSmall之後的敘述 } catch (WrongSize) { //捕捉WrongSize之後的敘述 } 絕大部分丟擲物件的語法都可以被丟擲字串的語法 所取代。