C++.NET面向對象程序設計CH8_第1頁
C++.NET面向對象程序設計CH8_第2頁
C++.NET面向對象程序設計CH8_第3頁
C++.NET面向對象程序設計CH8_第4頁
C++.NET面向對象程序設計CH8_第5頁
已閱讀5頁,還剩34頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第8章異常C++的異常處理機制能將異常檢測與異常處理分離開來,當異常發生時能自動調用異常處理程序進行錯誤處理。異常處理機制增加了程序的清晰性和可讀性,使程序員能夠編寫出清晰、健壯、容錯能力更強的程序,適用于大型軟件開發。本章主要介紹C++異常處理的語言機制,包括異常的結構、捕捉和處理,以及異常類。8.1異常處理概述商業軟件常會提供許多錯誤處理代碼,以便對各種可能出現錯誤的程序代碼進行檢測和處理,增加程序的健壯性。處理程序錯誤的代碼可能出現在源碼的任何地方,比如判定new是否成功分配內存、數據下標是否越界、運算溢出、除數0、無效參數等。錯誤處理代碼“污染”了程序源碼、大量的錯誤處理代碼使原本簡單的程序變得晦澀難懂。8.1異常處理概述2、傳統的異常處理方法傳統程序處理異常的典型方法是不斷測試程序繼續運行的必要條件,并對測試結果進行處理。形式如下偽碼所示:執行任務1if任務1未能被正確執行執行錯誤處理程序執行任務2if任務2未能正確執行執行錯誤處理程序執行任務3

缺點錯誤處理代碼分布在整個程序的各個部分,使程序受到了錯誤處理代碼的“污染”。8.1異常處理概述3、C++異常處理思想其基本思想是將異常發生和異常處理分別放在不同的函數中,產生異常的函數不需要具備處理異常的能力。當一個函數出現異常時,它可以拋出一個異常,然后由該函數的調用者捕獲并處理這個異常,如果調用者不能處理,它可以將該異常拋給其上一級的調用者處理。8.1異常處理概述4、C++的異常處理的作用改善程序的可讀性和可維護性,將異常處理代碼與主程序代碼分離,適合團隊開發大型項目。有力的異常檢測和可能的異常恢復,以統一方式處理異常。在異常引起系統錯誤之前處理異常。處理由庫函數引起的異常。在出現無法處理的異常時執行清理工作,并以適當的方式退出程序。在動態調用鏈中有序地傳播異常處理。8.2異常處理基礎8.2.1異常處理的結構try{…… //try程序塊

iferr1throwxx1……iferr2throwxx2……iferrnthrow

xxn}catch(type1arg){……} //異常類型1錯誤處理catch(type2arg){……} //異常類型2錯誤處理catch(typem

arg){……}//異常類型m錯誤處理……8.2異常處理基礎8.2.1異常處理的結構try{…… //try程序塊

iferr1throwxx1……iferr2throwxx2……iferrnthrow

xxn}catch(type1arg){……} //異常類型1錯誤處理catch(type2arg){……} //異常類型2錯誤處理catch(typem

arg){……}//異常類型m錯誤處理……8.2異常處理基礎8.2.1異常處理的結構try{…… //try程序塊

iferr1throwxx1……iferr2throwxx2……iferrnthrow

xxn}catch(type1arg){……} //異常類型1錯誤處理catch(type2arg){……} //異常類型2錯誤處理catch(typem

arg){……}//異常類型m錯誤處理……8.2異常處理基礎try-throw-catch異常處理的執行邏輯如下1、當程序執行過程中遇到try塊時,將進入try塊并按正常的程序邏輯順序執行其中的語句2、如果try塊的所有語句都被正常執行,沒有發生任何異常,那么try塊中就不會有異常被throw。在這種情況下,程序將忽略所有的catch塊,順序執行那些不屬于任何catch塊的程序語句,并按正常邏輯結束程序的執行,就像catch塊不存在一樣。8.2異常處理基礎3、如果在執行try塊的過程中,某條語句產生錯誤并用throw拋出了異常,則程序控制流程將自此throw子句轉移到catch塊,try塊中該throw語句之后的所有語句都不會再被執行了。4、C++將按catch塊出現的次序,用異常的數據類型與每個catch參數表中指定的數據類型相比較,如果兩者類型相同,就執行該catch塊,同時還將把異常的值傳遞給catch塊中的形參arg(如果該塊有arg形參)。只要有一個catch塊捕獲了異常,其余catch塊都將被忽略。5、如果沒有任何catch能夠匹配該異常,C++將調用系統默認的異常處理程序處理該異常,其通常做法是直接終止該程序的運行。【例8-1】異常處理的簡單例程。//CH8-1.cpp#include<iostream>usingnamespacestd;voidmain(){

cout<<"1--befroetryblock..."<<endl;try{

cout<<"2--Insidetryblock..."<<endl;throw10;

cout<<"3--Afterthrow...."<<endl;}

catch(inti){

cout<<"4--Incatchblock1...exception..errcodeis.."<<i<<endl;}

catch(char*s){

cout<<"5--Incatchblock2...exception..errcodeis.."<<s<<endl;}

cout<<"6--AfterCatch...";}8.2.2異常捕獲異常捕獲由catch完成,catch必須緊跟在與之對應的try塊后面。如果異常被某catch捕獲,程序將執行該catch塊中的代碼,之后將繼續執行catch塊后面的語句;如果異常不能被任何catch塊捕獲,它將被傳遞給系統的異常處理模塊,程序將被系統異常處理模塊終止。catch根據異常的數據類型捕獲異常,如果catch參數表中異常聲明的數據類型與throw拋出的異常的數據類型相同,該catch塊將捕獲異常。注意:catch在進行異常數據類型的匹配時,不會進行數據類型的默認轉換,只有與異常的數據類型精確匹配的catch塊才會被執行。8.2.2異常捕獲【例8-2】catch捕獲異常時,不會進行數據類型的默認轉換。//CH8-2.cpp#include<iostream>usingnamespacestd;voidmain(){

cout<<"1--befroetryblock..."<<endl;try{

cout<<"2--Insidetryblock..."<<endl;throw10;

cout<<"3--Afterthrow...."<<endl;}

catch(doublei){ //僅此與例8.1不同

cout<<"4--Incatchblock1..aninttypeis.."<<i<<endl;}

cout<<"5--AfterCatch...";}8.3異常與函數8.3.1在函數中處理異常異常處理可以局部化為一個函數,當每次進行該函數的調用時,異常將被重置。【例8-3】temperture是一個檢測溫度異常的函數,當溫度達到冰點或沸點時產生異常。#include<iostream>usingnamespacestd;voidtemperature(intt){try{

if(t==100)throw"沸點!";elseif(t==0)throw"冰點!";elsecout<<"thetemperatureisOK..."<<endl;}

catch(int

x){cout<<"temperatore="<<x<<endl;}

catch(char*s){cout<<s<<endl;}}voidmain(){temperature(0); //L1temperature(10); //L2temperature(100); //L3}8.3.2在函數調用中完成異常處理將產生異常的程序代碼放在一個函數中,將檢測處理異常的函數代碼放在另一個函數中,能讓異常處理更具靈活性和實用性。【例8-4】異常處理從函數中獨立出來,由調用函數完成。#include<iostream>usingnamespacestd;voidtemperature(intt){

if(t==100)throw"沸點!";elseif(t==0)throw"冰點!";elsecout<<"thetemperatureis..."<<t<<endl;}voidmain(){try{temperature(10);temperature(50);temperature(100);}

catch(char*s){cout<<s<<endl;}}增補(選講)限制函數異常限制異常的方法1、當一個函數聲明中不帶任何異常描述時,它可以拋出任何異常。例如:int

f(int,char);//函數f可以拋出任何異常2、在函數聲明的后面添加一個throw參數表,在其中指定函數可以拋出的異常類型。例如:int

g(int,char)throw(int,char);

//只允許拋出int和char異常。3、指定throw限制表為不包括任何類型的空表,不允許函數拋出任何異常。如:int

h(int,char)throw();//不允許拋出任何異常【例】設計函數Errhandler,限制它只能拋出int、char和double類型的異常。//Eg8.cpp#include<iostream>usingnamespacestd;voidErrhandler(int

n)throw(int,char,double){

if(n==1)thrown;

if(n==2)throw'x';

if(n==3)throw1.1;}voidmain(){

cout<<"BeforeErrhander..."<<endl;try{Errhandler(1);}

catch(inti){cout<<"catchaninteger..."<<endl;}

catch(char

c){cout<<"catchanchar..."<<endl;}

catch(double

d){cout<<"catchandouble..."<<endl;}}8.4異常處理的幾種特殊情況8.4.1捕獲所有異常在多數情況下,catch都只用于捕獲某種特定類型的異常,但它也具有捕獲全部異常的能力。其形式如下:catch(…){……//異常處理代碼}【例8】改寫前面的Errhandler函數,使之能夠捕獲所有異常。//CH.cpp#include<iostream>usingnamespacestd;voidErrhandler(int

n)throw(){try{

if(n==1)thrown;

if(n==2)throw"dx";

if(n==3)throw1.1;}

catch(…){cout<<"catchanexception..."<<endl;}}voidmain(){Errhandler(1);Errhandler(2);Errhandler(3);}8.4.2再次拋出異常如是catch塊無法處理捕獲的異常,它可以將該異常再次拋出,使異常能夠在恰當的地方被處理。再次拋出的異常不會再被同一個catch塊所捕獲,它將被傳遞給外部的catch塊處理。要在catch塊中再次拋出同一異常,只需在該catch塊中添加不帶任何參數的throw語句即可。【例8】在異常處理塊中再次拋出同一異常。//Eg8.cpp#include<iostream>usingnamespacestd;voidErrhandler(int

n)throw(){try{

if(n==1)thrown;

cout<<"allisok..."<<endl;}

catch(intn){

cout<<"catchanintexceptioninside..."<<n<<endl;

throw;//再次拋出本catch捕獲的異常

}}voidmain(){try{Errhandler(1);}

catch(intx){cout<<"catchintanexceptioninmain..."<<x<<endl;}

cout<<"....End..."<<endl;}8.4.3異常的嵌套調用try塊可以嵌套,即一個try塊中可以包括另一個try塊,這種嵌套可能形成一個異常處理的調用鏈。【例8-5】嵌套異常處理示例。//CH8-5.cpp#include<iostream>usingnamespacestd;voidfc(){

try{throw"help...";}

catch(int

x){cout<<"

hanlder"<<endl;}

try{cout<<"noerrorhandle..."<<endl;}

catch(char*px){cout<<"infc..char*hanlder"<<endl;}}

voidfb(){

int*q=newint[10];try{

fc();

cout<<"returnformfc()"<<endl;}catch(…){delete[]q;throw;}}voidfa(){char*p=newchar[10];try{

fb();

cout<<"returnfromfb()"<<endl;}catch(…){delete[]p;throw;}}voidmain(){try{

fa();

cout<<"returnfromfa"<<endl;}catch(…){cout<<"inmain"<<endl;}

cout<<"End"<<endl;}例8-5的調用過程8.5異常和類8.5.1構造函數與異常由于構造函數沒有返回類型,在執行構造函數過程中若出現異常,傳統處理方法可能是:返回一個處于錯誤狀態的對象,外部程序可以檢查該對象狀態,以便判定該對象是否被成功構造。設置一個全局變量保存對象構造的狀態,外部程序可以通過該變量值判斷對象構造的情況。在構造函數中不做對象的初始化工作,而是專門設計一個成員函數負責對象的初始化。C++中異常處理機制能夠很好地處理構造函數中的異常問題,當構造函數出現錯誤時就拋出異常,外部函數可以在構造函數之外捕獲并處理該異常。8.5異常和類【例8-6】類B有一個類A的對象成員數組obj,類B的構造函數進行了自由存儲空間的過量申請,最后造成內存資源耗盡產生

異常,則異常將調用對象成員數組obj的析構函數,回收obj占用的存儲空間。//CH8-6.cpp#include<iostream>usingnamespacestd;classA{

inta;public:

A(inti=0):a(i){}~A(){cout<<"inAdestructor..."<<endl;}};classB{Aobj[3];double*pb[10];public:

B(intk){cout<<"intBconstructor..."<<endl;for(inti=0;i<10;i++){pb[i]=newdouble[20000000];if(pb[i]==0)throwi;elsecout<<"Allocated20000000doublesinpb["<<i<<"]"<<endl;}}};voidmain(){try{Bb(2);}catch(int

e){cout<<"catchanexceptionwhenallocatedpb["<<e<<"]"<<endl;}}8.5.2異常類1、關于異常類異常可以是任何類型,包括自定義類。用來傳遞異常信息的類就是異常類。異常類可以非常簡單,甚至沒有任何成員;也可以同與普通類一樣復雜,有自己的成員函數、數據成員、構造函數、析構函數、虛函數等,還可以通過派生方式構成異常類的繼承層次結構。【例8-7】設計一個堆棧,當入棧元素超出了堆棧容量時,就拋出一個棧滿的異常;如果棧已空還要從棧中彈出元素,就拋出一個棧空的異常。//CH8-7.cpp#include<iostream>usingnamespacestd;constintMAX=3;classFull{}; //L1堆棧滿時拋出的異常類classEmpty{}; //L2堆棧空時拋出的異常類classStack{private:

int

s[MAX];

inttop;public:voidpush(inta);

intpop();

Stack(){top=-1;}};voidStack::push(inta){

if(top>=MAX-1)throwFull();

s[++top]=a;}int

Stack::pop(){

if(top<0)throwEmpty(); returns[top--];}voidmain(){Stacks;try{s.push(10);s.push(20);s.push(30);//s.push(40); //L5將產生棧滿異常

cout<<"stack(0)="<<s.pop()<<endl;

cout<<"stack(1)="<<s.pop()<<endl;

cout<<"stack(2)="<<s.pop()<<endl;

cout<<"stack(3)="<<s.pop()<<endl; //L6}

catch(Full){cout<<"Exception:StackFull"<<endl;}

catch(Empty){ cout<<"Exception:StackEmpty"<<endl;}}8.5.2異常類2.異常對象由異常類建立的對象稱為異常對象。異常類的處理過程實際上就是異常對象的生成與傳遞過程。如右圖【例8-8】修改例8-10的Full異常類,修改后的Full類具有構造函數和成員函數,還有一個數據成員。利用這些成員,可以獲取異常發生時沒有入棧的元素信息。//CH8-8.cpp#include<iostream>usingnamespacestd;constintMAX=3;classFull{

inta;public:

Full(int

i):a(i){}

int

getValue(){returna;}};classEmpty{};classStack{private:

int

s[MAX];

inttop;public:

Stack(){top=-1;}voidpush(inta){

if(top>=MAX-1)throwFull(a);

s[++top]=a;}

intpop(){

if(top<0)throwEmpty();returns[top--];}};voidmain(){Stacks;try{s.push(10);s.push(20); s.push(30);s.push(40);}

catch(Fulle){

cout<<"Exception:StackFull..."<<endl;

cout<<"Thevaluenotpushinstack:“<<e.getValue()<<endl;}}8.5.3派生異常類的處理在設計軟件的異常處理系統時,可以將各種異常匯集起來,根據異常的性質將其分屬到不同的類中,形成異常類的繼承體系結構。還可以利用類的多態性,將異常類設計為具有多態特性的繼承體系,利用多態的強大功能處理異常。一個進行遠程登錄訪問程序的異常類層次結構如圖。【例8-9】設計圖8-3所示異常繼承體系中從BasicException到FileSysException部分的異常類。//CH8-9.cpp#include<iostream>usingnamespacestd;classBasicException{public:char*Where(){return"BasicException...";}};classFileSysException:public

BasicException{public:char*Where(){return"FileSysException...";}};classFileNotFound:public

FileSysException{public:char*Where(){retur

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論