版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第十 異常處大型和十分復雜的程序往往會產生一些很難查找的甚至是大型和十分復雜的程序往往會產生一些很難查找的甚至是無法避免的運行時錯誤。當發(fā)生運行時錯誤時,不能簡單地結束程序運行,而是退回到任務的起點,錯誤,并由用戶決定下一步工作。面向對象的異常處理(ecepionhandling)機制是語言用以解決這個問題的有力工具。函數(shù)執(zhí)行時,放(測試)程序塊中的任何類型的數(shù)據(jù)對象發(fā)生異常,都可被thrw塊拋出,隨即沿調用鏈退回,直到被cach塊捕獲,并在此執(zhí)行異常處理,報告出現(xiàn)的異常等情況。從拋出到捕獲,應將各嵌套調用函數(shù)殘存在棧中的自動對象、自動量現(xiàn)保內等行除如果退到 函數(shù)還未捕獲則由bort(來終結 函數(shù)。第十 異常處10.1異常的10.1異常的概 異常處理的機10.5異常規(guī)10.3棧展開常捕 異常和繼10.410.4異常的重新拋和catch_all子 C++標準庫異常層次結異常的概這里所講的異常(exception)是 是無法確知怎樣發(fā)生和何時發(fā)生。特別在一個大型的程序(軟件)C++提供了一些內置的語言特性來產生(raise) 異常處理的首先,在C++中異常往往用類(class)為例,異常 如下classpopOnEmpty//棧空異常classpushOnFull{...};//棧滿異常測到棧滿或空就拋出一個異常template<typenameT>voidif(IsFull())throwelements[++top]=data;}template<typenameT>TStack<T>::Pop(){if(IsEmpty())throwpopOnEmpty<T>();returnelements[top--];}注意puhOnFul是類,C++要求拋出的必須是對象,所以必須有“”,即調用構造函數(shù)建立一個對象。異常處理的異常并非總是類對象,thow表達式也可以拋出任何類型的對象,如枚舉、整數(shù)等等。但最常用的是類對象。thow表達式拋出異常為異常處理的第一步。在堆棧的壓在中建立異常拋出與異常處理之間有一整套程序設計的機制。首先采用關鍵字tr,構成一個tr塊(tryblock),它包含了拋出異常異常處理的機請看下面的程序段給出try塊與catch子句的關系intinttry{for(i=0;i<9;i++)istack.PrintStack();}try{for(i=0;i<9;i++){b[i]=istack.Pop();}}for(i=0;i<9;i++)cout<<b[i]<<’\t’;return0;異常處理的機這里有兩個tr塊,分別對應壓棧與出棧;也有兩個catch子句(catchclause),分別處理壓棧時的棧滿和出棧時的???。由catch字句捕獲并處理異常是第二步。注意與ctch語句分別匹配thrw一個拋出pushOnFul類的無名對象,另一個拋出ppOnEmp類的無名對象。在編制程序時有一條慣例:把正常執(zhí)行的程序與異常處理兩。在上例中,我們可以把兩個tr塊合成一個,而把兩個ctch子句都放在函數(shù)最后。異常處理的機程序按下列規(guī)則控制如果沒有異常發(fā)生,繼續(xù)執(zhí)行ty塊中的代碼,與ty塊相關聯(lián)的catch子句被忽略,程序正常執(zhí)行,ain返回0。當?shù)谝粋€try塊在for循環(huán)中拋出異常,則該for循環(huán)退出,try塊也退出,去執(zhí)行pushOnFull異常的catch子句。如果第二個try塊調用Pop()拋出異常,則退出for和塊,去執(zhí)行popOnEmpty異常的catch子句當某條語句拋出異常時,跟在該語句后面的語句將被跳過。程序執(zhí)行權交給處理異常的cach子句,如果沒有atch子句能夠處理異常,則交給C+標準庫中定義的tinat。異常處理的機把程序的正常處理代碼和異常處理代碼分離的最清楚的方法是定義函數(shù)tr塊(fnctiontryblock)但V6.0不支持。intmain()intstack return0;catch(popOnEmpty<int>){cerr<<”??铡?lt;<endl;returncatch(pushOnFull<int>){cerr<<”棧滿”<<endl;return棧展開與異常捕catch子句由三部分組成:關鍵字catch、圓括號中的異常 以及復合語句中的一組語句。catchcatch子句不是函數(shù),所以圓括號中不是形參,而是一異常類 ,可以是類型也可以是對象catch子句的使用:它只有一個子句,沒有定義和調用分。使用時由系統(tǒng)按規(guī)則自動在catch子句列表中匹配catch子句可以包含返回語句(tun),也可不包含返回語句。包含返回語句,則整個程序結束含返回語句,則執(zhí)行ath列表之后的下一條語句。異 中也可以是一個對 。以棧為例當棧滿時,要求在異常對象中保存不能被壓入到棧中的值,這時,pshnul類可定義如下:template<typenameT>classpushOnFull{T_value;pushOnFull(T //或寫為pushOnFull(Ti){_value=i;}Tvalue(){return_value;}};新的私有數(shù)據(jù)成員_value保存值即調用構造函數(shù)時的實參對應在throw表達式中throw//data即Push(const&data)中的參數(shù)*catch子句異中采用對象只是一種形式。甚*catch子句異中采用對象只是一種形式。甚異常并非一個類對象時,也可以用同樣的格式,比異常為一枚舉量用類對象的公有成員在catch子句中,要取得_alu,須調用pushOnFull中的成員函數(shù)value:catch(pushOnFull<T>cerr<<”棧滿”<<eObj.value()<<”未壓入return在catch子句的異常 中 了對象Ob,用它來調用pushOnFu類的對象成員函數(shù)valu。異常對象是在拋出點被創(chuàng)建,與ctc子句是否顯式要求創(chuàng)建一個異常對象無關,該對象總是存在,在at子句中只是為了調用異常處理對象的成員函數(shù)才 為對象,不用類。棧展開與異常捕catch子句的異常與函數(shù)參數(shù)類似,可以值傳送,也可以是按傳遞。對大型類對象減少不必要的拷貝是很有意義的,所以對于類類型的異常,其異常最好也是被為。如:catch(pushOnFull<T>&return1;}使用 類型的異常 cach子句能夠修改異常對象,但僅僅是異常對象本身,正常程序部分的量并不會被修改與一般類對象不同,實際上異常對象處理完后,生命期也就結束了。只有需要重新拋出異常(在下一節(jié)中討論),修改操作才有意義。try塊相關聯(lián)的catch子句列表則處理該異常;沒有,則查找過程在該函數(shù)的主調函數(shù)中繼續(xù)進行。即這個查找過一個匹配的catch子句,就進入該catch子句,進行處理查找過程結束棧展開與異常捕展開(stackunwinding)。這是異常處理的 在棧異常處理的例子中,對ppOn,首先應在istack的成員函數(shù)Pop中找,因為Pop中的tw表達式沒有在塊中,所以Pop帶著一個異常退出。下一步是檢查調用Pop的函數(shù),這里是ain(,在ain(中對op的調用位于一個塊中,則可用與該塊關聯(lián)的cach子句列表中的某一個來處理,找到第一個popnEmp類型異常聲明的cach子句,并進入該子句進行異常處理。而且可能逆調用鏈而上,甚至整個任務。因此,異常處理應該在其對程序影響的終結處進行,甚至是在調用該任務的菜單處進行。棧展開與異常捕退出調用鏈時必須釋放所有資源,由系統(tǒng)回收在棧展開期間,在退出的域中有某個局部量是類對象,棧展異常處理過程本質上反映的是“資源獲取是由構造函數(shù)實現(xiàn),而資源釋放是由析構函數(shù)完成”。采用面向對象的程序設計,取得資源的動作封裝在類的構造函數(shù)中,釋放資源的動作封裝在類的析構函數(shù)中,當一個函數(shù)帶著未處理的異常退出時,函數(shù)中這種類對象被自動銷毀,資源(包括動態(tài)空間分配的資源和打開的文件釋放。所以由文件重構對象應該放在構造函數(shù)中,把對象存入文件應該放在析構函數(shù)中。異常處理應該用于面向對象的程序設計。對非面向對象的程序設計如果函數(shù)動態(tài)獲得過資源,因異常,這些資源的釋放語句可能被忽略,則這些資源將不會被自動釋放。棧展開與異常捕異常對象是在tw表達式中建立并拋出:tw表然后把這個臨時對象拷貝到一個被稱為異常對象(exceptionobject)的存貯區(qū)中,它保證會持續(xù)異常被處理完 棧展開與異常捕函數(shù)調用和異常處理的主要區(qū)別是建立函數(shù)調用所需要的全部信息在編譯時已經獲得,而異常處理機制要求運行時的支持。對于普通函數(shù)調用,通過函數(shù)重載解析過程,編譯器知道在調用點上哪個函數(shù)會真正被調用。但對于異常處理,編譯器不知道特定的tw表達式的catch子句在哪個函數(shù)中,以及在處理異常之后執(zhí)行權被轉移到哪兒。這些都在運行時刻決定,異常是隨機發(fā)生的,異常處理的catch子句是沿調用鏈逆向進行查找,這與運行時的多態(tài)編譯器無法通知用戶,所以要有eae函數(shù),它是一種運行機制,當沒有處理代碼(ctch子句)能夠匹配,被拋出的異常時由它通知用戶。異常的重新拋出和catch_all子當catch語句捕獲一個異常后,可能不能完全處理完成某些操作后,該異常必須由函數(shù)鏈中更的函數(shù)來處理,這時ach子句可以重新拋出(ethr)該異常,把異常傳遞給函數(shù)調用鏈中更的另一個cach子句,由它進行進一步處理。但僅有一個關鍵字,因為異常類型在catch語句中已經有了,不必再指明。被新出異就原的常象。但是重新拋出異常的cach子句應該把自己做過的工作告訴下一個處理異常的catch子句,往往要對異常對象做一定修改,以表達某些信息,因此ath子句中的異常 必須被 為 ,這樣修改才能真正做在異常對象自身中,而不是拷貝中。異常的重新拋出和catch_all子通用形式的catch子句catch(...){代碼任何異常都可以進入這個catch為省略號?;ɡㄌ栔械膹秃险Z句用來執(zhí)行指定操作異常發(fā)生后按棧展開(stackunwinding)退出,動態(tài)分配的非voidfun1(){int*res;res=newint[100//定義一個資源對try{//代碼包括使用資源res和某些可能引起異常拋出的操 //異常可能有多catch(...){//不論是那種異常都在此釋放delete[]res;//釋放資源對象resthrow;}//重新拋出異常deleteres;//正常退出前釋放資源對象異常的重新拋出和catch_all子cac_all子句可以單獨使用,也可以與其它cach子句聯(lián)合使用。如果聯(lián)合使用,它必須放在相關子句表的最后。catch子句被檢查的順序與它們在try塊之后排列順序相同,一旦找到了一個匹配,則后續(xù)的ach子句將不再檢查,按此規(guī)則,catch_all子句(cach(...){})處理表前面所列各種異常之外的異常。如果只用catch_all子句進行某項操作,則其他的操作應由catch子句重新拋出異常,沿調用鏈逆向去查找新的處理子句來處理,不能在子句列表中再按排一個處理同一異常的子句,因為第二個子句是 執(zhí)行不到的。異常規(guī)范(exceptionspecification)提供函數(shù)(函數(shù)指針 列出該函數(shù)可能拋出的異常
案不會拋出任何其他類型的異常,在stack類定義中可有viodPush(constT&data)throw(pushOnFull,Over,int,double)TPop()throw(popOnEmpty);成員函數(shù)類內 和類外定義必須必須在兩處都有相同的異常規(guī)同樣的異常規(guī)范。一個函數(shù)的異常規(guī)范的違例只能在運行時才能被檢測出來。如果在運行時,函數(shù)拋出了一個沒有被列在它的異常規(guī)范中的異常時(并且函數(shù)中所拋出的異常,沒有在該函數(shù) 理)則系統(tǒng)調用標準庫中定義的函unexpcted(。如果異常規(guī)范為tw(,則表示不得拋出任何異常。必 VC++6.0不支持異常規(guī)學習了前幾節(jié)內容后,給出下例作為小【例10.1】包含棧滿或空異常在C++程序中,表示異常的類通常被組成為一個(即 面各節(jié)討論的那樣)或者一個層次結構classExcp{public:voidprint(stringmsg){cerr<<msg<<endl;}};再從該基類派生出兩個異常類classstackExcp:publicExcp{...};//棧異常類的基類classmathExcp:publicExcp{..//數(shù)學庫異常的基類classpopOnEmpty:publicstackExcp{...};//棧空退棧異常classpushOnFull:publicstackExcp{...};//棧滿壓棧異常classzeroOp:publicmathExcp{...};//數(shù)學 classdivideByZero:publicmathExcp{...};//數(shù)學庫被零除異常形成了三層結構 在層次結構下,異常的拋出會有一些不同,以下做法是錯的pushOnFullstackExcp*pse=&except//pse指向的類對象為pushOnFullthrow*pse;}//拋出的異常對象的類型為stackExcp這里被創(chuàng)建的異常類對象sackxcp類類型,盡管pe指向一個實際類型pushnFul的對象,但那是一個臨時對象,拷貝到異常對象的 區(qū)中時創(chuàng)建的卻sackxcp類的異常對象。所以該異常不能被puhOnFul類型的cach子句處理。 catch(pushOnFull){...}//處理pushOnFull異常catch(stackExcp){...}//處理棧的其他異常catch(Excp//處理一般異catch(…)派生類類型的catch子句必須先出現(xiàn),以確保只有在沒有其catch子句適用時,才會進入基類類型的catch異常catch子句不必是與異常最匹配的atch子句,而是最先匹配到的catch子句,就是第一個遇到的可以處理該異常的catch子句。所以在atch子句列表中最特化的(匹配條件最嚴格的)cach子句必須先出現(xiàn)。虛函數(shù)是類層次結構中多態(tài)性的基 ,異類層次結構中也可以定義虛擬函數(shù) 類層次結構的異常同樣可以重新拋出(rethrow),把一個常傳遞給函數(shù)調用列表中更上層的另一個catchpushOnFull類類型的異常,而它被基類的ctch子句處理,并在其中再次被拋出,那么這個異常仍是phOnul類類型的異常,而不是其基類類型的異常。在基catch子句處理的是異常對象的基類子對象的一份拷貝該拷貝只在該catc子句中被 ,重新拋出的是原來的異常對象。這個放在異常對象 區(qū)中的異常的生命期應該是在處理該異常的一系列的子句中最后一個退出時才結束,也是直到這時,才由異常類的析構函數(shù)來銷毀它。這一系列的子句是由重新拋出聯(lián)系起來的?!纠?0.2】異常層次結構中的虛函數(shù)。為了調用派生類對的虛擬函數(shù),異常 必須為一個指針或虛函數(shù)中異常規(guī)范可以不同。派生類的虛擬必須與基類虛函數(shù)的異常一樣或更嚴格(是基類虛函數(shù)的異常的子集)。因為當派生類的虛函數(shù)被指向基類類型的指針調用時,保證不會違背基類成員函數(shù)的異常規(guī)范。classCBase{virtualintfun1(int)throw();virtualintfun2(int)throw(int);virtualstringfun3() classCDerived:publicCBase{intfun1(int)//錯!異常規(guī)范不如throw()嚴intfun2(int)throw(int);//對!有相同的異stringfun3()throw(string);//對!異常規(guī)范throw(int,string)更嚴C++標準庫中的異常層次的根類被稱為定義在庫的頭文件<exception>exception類的接口如下namespacestd//注意在名字空間域stdclassexception()throw//缺省構造函exception(constexception&)throw()//拷貝構造函exception&operator=(constexception&)throw()//拷貝賦值操作virtual~exception()throw();//析構函數(shù)virtualconstchar*what() throw()//返回一個C} C++標準庫提供的邏輯異常包括inalid_aent異常,接收到一個無效的實參,拋出該異常。ou_o_ange異常,收到一個不在預期范圍中的實參,則拋出。lenh_er異常,報告企圖產生“長度值超出最大允許值”的對象 以上三個異常是由runtime_error類派生的異常。當ew()操作符不能分配所要求 區(qū)時,會出該異常。它是由基類exception派生的【例10.3】為類模板Array重新定義operator[](),如索引值越界,它會拋出一個out_of_range類型的異常第十 異常處完謝謝[例10.1]堆棧異常處template<typenameT>classpushOnFull{//棧滿異常T_value;pushOnFull(Ti){_value=i;}Tvalue(){return_value;}template<typenameT>classpopOnEmpty{//棧空異voidprint(){cerr<<"棧已空,無法出棧[例10.1]堆棧異常處template<typenameT>classinttop; T //動態(tài)建立的數(shù)int //棧最大允納 //棧如不指定大小,設為20元~Stack(){delete[]voidPush(constT&data)throw(pushOnFull<T//壓TPop()throw(popOnEmpty); TGe em(inti){returnelements[i];}//返回指定元素voidMakeEmpty(){top=-1;} boolIsEmpty()const{returntop==-1;} boolIsFull()const{returntop==maxSize-1;} voidPrintStack(); [例10.1]堆棧異常處template<typenameT>voidStack<T>::Push(constTif(IsFull())throwpushOnFull<T>(data);//棧滿則拋出異//棧頂指針先加1,元素再進棧,top是指向棧頂元}template<typenameT>TStack<T>::Pop()if(IsEmpty())throw//棧已空則不能退棧,拋出異returnelements[top--];//返回棧頂元素,同時棧頂指針退}[例10.1]堆棧異常處intinta[9]={1,2,3,4,5,6,7,8,9},for(i=0;i<9;i++)istack.Push(a[i]//到a[8]時棧滿,異}try{for(i=0;i<9;i++)b[i]=istack.Pop();}catch(popOnEmpty<int>&eObj){eObj.print();}for(i=0;i<9;i++)cout<<b[i]<<'\t';return0;}[例10.2]異常層次結構中的虛函class virtualvoidprint(){cerr<<"發(fā)生異常classstackExcp:public virtualvoidprint(){cerr<<"棧發(fā)生異常classpushOnFull:public virtualvoidprint(){cerr<<"棧滿,不能壓棧classpopOnEmpty:public void
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- GB/T 33223-2024軋制設備術語
- Target-Protein-Ligand-Linker-Conjugates-4-生命科學試劑-MCE-5926
- 1-2-Dihexanoyl-sn-glycero-3-PS-sodium-生命科學試劑-MCE-8684
- 二零二五年度離婚協(xié)議書中共同財產清算起訴狀
- 2025年度電力市場交易購售電合同
- 二零二五年度大型賽事活動合作2025年度營銷合同
- 二零二五年度私人住宅裝修質量與安全雙保障協(xié)議
- 2025年度離婚子女債務償還與財產分割執(zhí)行協(xié)議
- 2025年度煙酒企業(yè)社會責任履行與公益合作合同
- 二零二五年度文化創(chuàng)意產業(yè)銀行擔保協(xié)議
- 北京市海淀區(qū)2024-2025學年八年級上學期期末考試數(shù)學試卷(含答案)
- 2025年廣西柳州市中級人民法院招錄聘用工作人員17人高頻重點提升(共500題)附帶答案詳解
- 2024年全國職業(yè)院校技能大賽高職組(研學旅行賽項)考試題庫(含答案)
- 十八項核心制度
- 2025年物業(yè)公司安全生產工作計劃(5篇)
- 2025社保政策培訓
- 電器儀表人員培訓課件
- 2025年中小學春節(jié)安全教育主題班會課件
- 2023年工程制圖習題集
- 計量經濟學練習題
- 2025年全國高考體育單招考試模擬政治試卷試題(含答案詳解)
評論
0/150
提交評論