c++-unit10異常處理市公開課一等獎(jiǎng)省賽課微課金獎(jiǎng)?wù)n件_第1頁(yè)
c++-unit10異常處理市公開課一等獎(jiǎng)省賽課微課金獎(jiǎng)?wù)n件_第2頁(yè)
c++-unit10異常處理市公開課一等獎(jiǎng)省賽課微課金獎(jiǎng)?wù)n件_第3頁(yè)
c++-unit10異常處理市公開課一等獎(jiǎng)省賽課微課金獎(jiǎng)?wù)n件_第4頁(yè)
c++-unit10異常處理市公開課一等獎(jiǎng)省賽課微課金獎(jiǎng)?wù)n件_第5頁(yè)
已閱讀5頁(yè),還剩35頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第十章異常處理

大型和十分復(fù)雜程序往往會(huì)產(chǎn)生一些極難查找甚至是無(wú)法防止運(yùn)行時(shí)錯(cuò)誤。當(dāng)發(fā)生運(yùn)行時(shí)錯(cuò)誤時(shí),不能簡(jiǎn)單地結(jié)束程序運(yùn)行,而是退回到任務(wù)起點(diǎn),指犯錯(cuò)誤,并由用戶決定下一步工作。面向?qū)ο螽惓L幚恚╡xceptionhandling)機(jī)制是C++語(yǔ)言用以處理這個(gè)問(wèn)題有力工具。

函數(shù)執(zhí)行時(shí),放在try(測(cè)試)程序塊中任何類型數(shù)據(jù)對(duì)象發(fā)生異常,都可被throw表示式拋出,隨即逆調(diào)用鏈退回,直到被catch子句捕捉,并在此執(zhí)行異常處理,匯報(bào)出現(xiàn)異常等情況。從拋出到捕捉,應(yīng)將各嵌套調(diào)用函數(shù)殘余在棧中自動(dòng)對(duì)象、自動(dòng)變量和現(xiàn)場(chǎng)保護(hù)內(nèi)容等進(jìn)行去除。假如已退到入口函數(shù)還未捕捉則由terminate()函數(shù)來(lái)終止入口函數(shù)。1/40第十章異常處理10.1異常概念

10.3棧展開與異常捕捉

10.2異常處理機(jī)制

10.5異常和繼承

10.7C++標(biāo)準(zhǔn)庫(kù)異常類層次結(jié)構(gòu)

(選讀)10.6異常規(guī)范(選讀)10.4異常重新拋出和catch_all子句

2/4010.1

異常概念

異常概念引入:

異常(exception)是程序可能檢測(cè)到,運(yùn)行時(shí)不正常情況,如存放空間耗盡、數(shù)組越界、被0除等等。能夠預(yù)見可能發(fā)生在什么地方,不過(guò)無(wú)法確知怎樣發(fā)生和何時(shí)發(fā)生。尤其在一個(gè)大型程序(軟件)中,程序各部分是由不一樣小組編寫,它們由公共接口連起來(lái),錯(cuò)誤可能就發(fā)生在相互配合上,也可能發(fā)生在事先根本想不到個(gè)別條件組合上。C++提供了一些內(nèi)置語(yǔ)言特征來(lái)產(chǎn)生(raise)或拋出(throw)異常,用以通知“異常已經(jīng)發(fā)生”,然后由預(yù)先安排程序段來(lái)捕捉(catch)異常,并對(duì)它進(jìn)行處理。這種機(jī)制能夠在C++程序兩個(gè)無(wú)關(guān)(往往是獨(dú)立開發(fā))部分進(jìn)行“異常”通信。由程序某一部分引發(fā)了另一部分異常,這一異??苫氐揭l(fā)異常部分去處理(逆著程序函數(shù)調(diào)用鏈)。3/4010.2

異常處理機(jī)制測(cè)到棧滿或空就拋出一個(gè)異常。template<typenameT>voidStack<T>::Push(constT&data){

if(IsFull())throwpushOnFull<T>(data);

//注意加了括號(hào),是結(jié)構(gòu)一個(gè)無(wú)名對(duì)象

elements[++top]=data;}template<typenameT>TStack<T>::Pop(){

if(IsEmpty())throwpopOnEmpty<T>();

returnelements[top--];}注意pushOnFull是類,C++要求拋出必須是對(duì)象,所以必須有“()”,即調(diào)用結(jié)構(gòu)函數(shù)建立一個(gè)對(duì)象。異常與異常拋出:以棧為例,異常類申明以下:classpopOnEmpty{...};//棧空異常classpushOnFull{...};//棧滿異常4/4010.2

異常處理機(jī)制throw表示式拋出異常為異常處理第一步。在堆棧壓棧和出棧操作中發(fā)生錯(cuò)誤而拋出異常,理所當(dāng)然地應(yīng)由調(diào)用堆棧程序來(lái)處理。異常并非總是類對(duì)象,throw表示式也能夠拋出任何類型對(duì)象,如枚舉、整數(shù)等等。但最慣用是類對(duì)象。在C++中異常拋出與異常處理之間有一整套程序設(shè)計(jì)機(jī)制。首先采取關(guān)鍵字try,組成一個(gè)try塊(tryblock),它包含了拋出異常語(yǔ)句。當(dāng)然也能夠是包含了這么調(diào)用語(yǔ)句,該語(yǔ)句所調(diào)用函數(shù)中有能夠拋出異常語(yǔ)句。異常處理機(jī)制:5/4010.2

異常處理機(jī)制intmain(){

inta[9]={1,2,3,4,5,6,7,8,9},b[9]={0},i;stack<int>istack(8);

try{for(i=0;i<9;i++)istack.Push(a[i]);istack.PrintStack();}

catch(pushOnFull<int>){cerr<<”棧滿”<<endl;}

try{for(i=0;i<9;i++){b[i]=istack.Pop();}}

catch(popOnEmpty<int>){cerr<<”??铡?lt;<endl;}

for(i=0;i<9;i++)cout<<b[i]<<’\t’;cout<<endl;

return0;}try塊與catch子句關(guān)系實(shí)例:6/4010.2

異常處理機(jī)制由catch字句捕捉并處理異常是第二步。注意與catch語(yǔ)句分別匹配是在壓棧和出棧組員函數(shù)模板中throw語(yǔ)句,一個(gè)拋出pushOnFull類無(wú)名對(duì)象,另一個(gè)拋出popOnEmpty類無(wú)名對(duì)象。在編制程序時(shí)有一條通例:把正常執(zhí)行程序與異常處理兩部分分隔開來(lái),這么使代碼更易于跟隨和維護(hù)。在上例中,我們能夠把兩個(gè)try塊合成一個(gè),而把兩個(gè)catch子句都放在函數(shù)最終。

說(shuō)明:這里有兩個(gè)try塊,分別對(duì)應(yīng)壓棧與出棧;也有兩個(gè)catch子句(catchclause),分別處理壓棧時(shí)棧滿和出棧時(shí)???。

7/4010.2

異常處理機(jī)制1.假如沒有異常發(fā)生,繼續(xù)執(zhí)行try塊中代碼,與try塊相關(guān)聯(lián)catch子句被忽略,程序正常執(zhí)行,main()返回0。2.當(dāng)?shù)谝粋€(gè)try塊在for循環(huán)中拋出異常,則該for循環(huán)退出,try塊也退出,去執(zhí)行可處理pushOnFull異常catch子句。istack.PrintStack()不再執(zhí)行,被忽略。3.假如第二個(gè)try塊調(diào)用Pop()拋出異常,則退出for和try塊,去執(zhí)行可處理popOnEmpty異常catch子句。4.當(dāng)某條語(yǔ)句拋出異常時(shí),跟在該語(yǔ)句后面語(yǔ)句將被跳過(guò)。程序執(zhí)行權(quán)交給處理異常catch子句,假如沒有catch子句能夠處理異常,則交給C++標(biāo)準(zhǔn)庫(kù)中定義terminate()。流程控制規(guī)則:8/4010.3棧展開與異常捕捉

catch子句由三部分組成:關(guān)鍵字catch、圓括號(hào)中異常申明以及復(fù)合語(yǔ)句中一組語(yǔ)句。catch子句不是函數(shù),所以圓括號(hào)中不是形參,而是一個(gè)異常類型申明,能夠是類型也能夠是對(duì)象。catch子句使用:它只有一個(gè)子句,沒有定義和調(diào)用之分。使用時(shí)由系統(tǒng)按規(guī)則自動(dòng)在catch子句列表中匹配。

catch子句能夠包含返回語(yǔ)句(return),也可不包含返回語(yǔ)句。包含返回語(yǔ)句,則整個(gè)程序結(jié)束。而不包含返回語(yǔ)句,則執(zhí)行catch列表之后下一條語(yǔ)句。

catch子句說(shuō)明:當(dāng)try塊中語(yǔ)句拋出異常時(shí),系統(tǒng)經(jīng)過(guò)查看跟在其后catch子句列表,來(lái)查找可處理該異常catch子句。9/4010.3棧展開與異常捕捉對(duì)應(yīng)在throw表示式中,結(jié)構(gòu)拋出對(duì)象也要有實(shí)參:throwpushOnFull(data);

//data即Push(const&data)中參數(shù)datatemplate<typenameT>classpushOnFull{T_value;public:pushOnFull(Ti):_value(i){}

//或?qū)憺閜ushOnFull(Ti){_value=i;}Tvalue(){return

_value;}};新私有數(shù)據(jù)組員_value保留那些不能被壓入棧中值。該值即調(diào)用結(jié)構(gòu)函數(shù)時(shí)實(shí)參。catch子句異常申明探討:異常申明中能夠是一個(gè)對(duì)象申明。以棧為例。當(dāng)棧滿時(shí),要求在異常對(duì)象中保留不能被壓入到棧中值,pushOnFull類可定義以下:10/4010.3棧展開與異常捕捉

在catch子句中,要取得_value,須調(diào)用pushOnFull

中組員函數(shù)value():catch(pushOnFull<T>eObj){cerr<<”棧滿”<<eObj.value()<<”未壓入棧”<<endl;

return1;}在catch子句異常申明中申明了對(duì)象eObj,用它來(lái)調(diào)用pushOnFull類對(duì)象組員函數(shù)value()。異常對(duì)象是在拋出點(diǎn)被創(chuàng)建,與catch子句是否顯式要求創(chuàng)建一個(gè)異常對(duì)象無(wú)關(guān),該對(duì)象總是存在,在catch子句中只是為了調(diào)用異常處理對(duì)象組員函數(shù)才申明為對(duì)象,不用類。*catch子句異常申明中采取對(duì)象只是一個(gè)形式。甚至異常并非一個(gè)類對(duì)象時(shí),也能夠用一樣格式,比如異常為一枚舉量,這時(shí)就等效于按值傳遞,而不是調(diào)用類對(duì)象公有組員。11/4010.3棧展開與異常捕捉catch子句異常申明與函數(shù)參數(shù)申明類似,能夠是按值傳送,也能夠是按引用傳遞。對(duì)大型類對(duì)象降低無(wú)須要復(fù)制是很有意義,所以對(duì)于類類型異常,其異常申明最好也是被申明為引用。如:catch(pushOnFull<T>&eObj){cerr<<”棧滿”<<eObj.value()<<”未壓?!?lt;<endl;

return1;}使用引用類型異常申明,catch子句能夠修改異常對(duì)象,但僅僅是異常對(duì)象本身,正常程序部分量并不會(huì)被修改。與普通類對(duì)象不一樣,實(shí)際上異常對(duì)象處理完后,生命期也就結(jié)束了。只有需要重新拋出異常(在下一節(jié)中討論),修改操作才有意義。

【例10.1】包含棧滿或空異常完整程序。12/4010.3棧展開與異常捕捉把程序正常處理代碼和異常處理代碼分離最清楚方法是定義函數(shù)try塊(FunctiontryBlock)。這種方法是把整個(gè)函數(shù)包含在try塊中。

一個(gè)函數(shù)try塊把一組catch子句同一個(gè)函數(shù)體相關(guān)聯(lián)。假如函數(shù)體中語(yǔ)句拋出一個(gè)異常,則考慮跟在函數(shù)體后面處理代碼來(lái)處理該異常。函數(shù)try塊對(duì)結(jié)構(gòu)函數(shù)尤其有用。【例10.1_1】定義函數(shù)try塊(FunctiontryBlock)。

函數(shù)try塊使用:13/40尋找匹配catch子句有固定過(guò)程:假如throw表示式位于try塊中,則檢驗(yàn)與try塊相關(guān)聯(lián)catch子句列表,看是否有一個(gè)子句能夠處理該異常,有匹配,則該異常被處理;找不到匹配catch子句,則在主調(diào)函數(shù)中繼續(xù)查找。假如一個(gè)函數(shù)調(diào)用在退出時(shí)帶有一個(gè)被拋出異常未能處理,而且這個(gè)調(diào)用位于一個(gè)try塊中,則檢驗(yàn)與該try塊相關(guān)聯(lián)catch子句列表,看是否有一個(gè)子句匹配,有,則處理該異常;沒有,則查找過(guò)程在該函數(shù)主調(diào)函數(shù)中繼續(xù)進(jìn)行。即這個(gè)查找過(guò)程逆著嵌套函數(shù)調(diào)用鏈向上繼續(xù),直到找處處理該異常catch子句。只要碰到第一個(gè)匹配catch子句,就會(huì)進(jìn)入該catch子句,進(jìn)行處理,查找過(guò)程結(jié)束。

14/4010.3棧展開與異常捕捉

在棧異常處理例子中,對(duì)popOnEmpty,首先應(yīng)在istack組員函數(shù)Pop()中找,因?yàn)镻op()中沒有try塊,不存在catch子句,所以Pop()帶著一個(gè)異常退出。下一步是檢驗(yàn)調(diào)用Pop()函數(shù),這里是main(),在main()中對(duì)Pop()調(diào)用位于一個(gè)try塊中,則可用與該try塊關(guān)聯(lián)catch子句列表中某一個(gè)來(lái)處理,找到第一個(gè)popOnEmpty類型異常申明catch子句,并進(jìn)入該子句進(jìn)行異常處理。

棧展開:因發(fā)生異常而逐步退出復(fù)合語(yǔ)句和函數(shù)定義過(guò)程,被稱為棧展開(stackunwinding)。這是異常處理關(guān)鍵技術(shù)。異常對(duì)程序影響通常不但是在發(fā)生異常那個(gè)局部范圍中,而且可能逆調(diào)用鏈而上,甚至整個(gè)任務(wù)。所以,異常處理應(yīng)該在其對(duì)程序影響終止處進(jìn)行,甚至是在調(diào)用該任務(wù)菜單處進(jìn)行。15/4010.3棧展開與異常捕捉

在棧展開期間,在退出域中有某個(gè)局部量是類對(duì)象,棧展開過(guò)程將自動(dòng)調(diào)用該對(duì)象析構(gòu)函數(shù),完成資源釋放。所以C++異常處理過(guò)程本質(zhì)上反應(yīng)是“資源獲取是由結(jié)構(gòu)函數(shù)實(shí)現(xiàn),而資源釋放是由析構(gòu)函數(shù)完成”。采取面向?qū)ο蟪绦蛟O(shè)計(jì),取得資源動(dòng)作封裝在類結(jié)構(gòu)函數(shù)中,釋放資源動(dòng)作封裝在類析構(gòu)函數(shù)中,當(dāng)一個(gè)函數(shù)帶著未處理異常退出時(shí),函數(shù)中這種類對(duì)象被自動(dòng)銷毀,資源(包含動(dòng)態(tài)空間分配資源和打開文件)釋放。所以由文件重構(gòu)對(duì)象應(yīng)該放在結(jié)構(gòu)函數(shù)中,把對(duì)象存入文件應(yīng)該放在析構(gòu)函數(shù)中。棧展開時(shí)資源釋放:異常處理應(yīng)該用于面向?qū)ο蟪绦蛟O(shè)計(jì)。對(duì)非面向?qū)ο蟪绦蛟O(shè)計(jì)假如函數(shù)動(dòng)態(tài)取得過(guò)資源,因異常,這些資源釋放語(yǔ)句可能被忽略,則這些資源將永遠(yuǎn)不會(huì)被自動(dòng)釋放。16/4010.3棧展開與異常捕捉

異常不能夠保持在未被處理狀態(tài)。異常表示一個(gè)程序不能夠繼續(xù)正常執(zhí)行,這是非常嚴(yán)重問(wèn)題,假如沒有找處處理代碼,程序就調(diào)用C++標(biāo)準(zhǔn)庫(kù)中定義函數(shù)terminate()。異常對(duì)象探討:異常對(duì)象是在throw表示式中建立并拋出:throw表示式經(jīng)過(guò)調(diào)用異常類結(jié)構(gòu)函數(shù)創(chuàng)建一個(gè)暫時(shí)對(duì)象,然后把這個(gè)暫時(shí)對(duì)象復(fù)制到一個(gè)被稱為異常對(duì)象(exceptionobject)存貯區(qū)中,它確保會(huì)連續(xù)到異常被處理完。

17/4010.3棧展開與異常捕捉函數(shù)調(diào)用和異常處理區(qū)分:建立函數(shù)調(diào)用所需要全部信息在編譯時(shí)已經(jīng)取得,而異常處理機(jī)制要求運(yùn)行時(shí)支持。對(duì)于普通函數(shù)調(diào)用,經(jīng)過(guò)函數(shù)重載解析過(guò)程,編譯器知道在調(diào)用點(diǎn)上哪個(gè)函數(shù)會(huì)真正被調(diào)用。但對(duì)于異常處理,編譯器不知道特定throw表示式catch子句在哪個(gè)函數(shù)中,以及在處理異常之后執(zhí)行權(quán)被轉(zhuǎn)移到哪兒。這些都在運(yùn)行時(shí)刻決定,異常是隨機(jī)發(fā)生,異常處理catch子句是逆調(diào)用鏈進(jìn)行查找,這與運(yùn)行時(shí)多態(tài)-——虛函數(shù)也是不一樣。當(dāng)一個(gè)異常不存在處理代碼時(shí),系統(tǒng)無(wú)法通知用戶,所以要有terminate()函數(shù),它是一個(gè)運(yùn)行機(jī)制,當(dāng)沒有處理代碼(catch子句)能夠匹配,被拋出異常時(shí)由它通知用戶。18/4010.4異常重新拋出和catch_all子句(選讀)

rethrow表示式仍為:throw;

但僅有一個(gè)關(guān)鍵字,因?yàn)楫惓n愋驮赾atch語(yǔ)句中已經(jīng)有了,無(wú)須再指明。被重新拋出異常就是原來(lái)異常對(duì)象。不過(guò)重新拋出異常catch子句應(yīng)該把自己做過(guò)工作告訴下一個(gè)處理異常catch子句,往往要對(duì)異常對(duì)象做一定修改,以表示一些信息,所以catch子句中異常申明必須被申明為引用,這么修改才能真正做在異常對(duì)象本身中,而不是副本中。

異常重新拋出與連續(xù)處理:當(dāng)catch語(yǔ)句捕捉一個(gè)異常后,可能不能完全處理異常,完成一些操作后,該異常必須由函數(shù)鏈中更上級(jí)函數(shù)來(lái)處理,這時(shí)catch子句能夠重新拋出(rethrow)該異常,把異常傳遞給函數(shù)調(diào)用鏈中更上級(jí)另一個(gè)catch子句,由它進(jìn)行深入處理。19/4010.4異常重新拋出和catch_all子句(選讀)通用catch子句(catch_all):catch(...){代碼*/}

任何異常都能夠進(jìn)入這個(gè)catch子句。這里三個(gè)點(diǎn)稱為省略號(hào)?;ɡㄌ?hào)中復(fù)合語(yǔ)句用來(lái)執(zhí)行指定操作。異常發(fā)生后按棧展開(stackunwinding)退出,動(dòng)態(tài)分配非類對(duì)象資源不會(huì)自動(dòng)釋放,通常在catch_all子句中釋放。voidfun1(){

int*res;res=newint[100];//定義一個(gè)資源對(duì)象

try{//代碼包含使用資源res和一些可能引發(fā)異常拋出操作

}//異??赡苡懈鞣N

catch(...){//不論是那種異常都在此釋放

delete[]res;//釋放資源對(duì)象res

throw;}//重新拋出異常

delete[]res;}//正常退出前釋放資源對(duì)象res;20/4010.4異常重新拋出和catch_all子句(選讀)

catch_all子句能夠單獨(dú)使用,也能夠與其它c(diǎn)atch子句聯(lián)合使用。假如聯(lián)合使用,它必須放在相關(guān)catch子句表最終。

catch子句被檢驗(yàn)次序與它們?cè)趖ry塊之后排列次序相同,一旦找到了一個(gè)匹配,則后續(xù)catch子句將不再檢驗(yàn),按此規(guī)則,catch_all子句(catch(...){})處理表前面所列各種異常之外異常。假如只用catch_all子句進(jìn)行某項(xiàng)操作,則其它操作應(yīng)由catch子句重新拋出異常,逆調(diào)用鏈去查找新處理子句來(lái)處理,不能在子句列表中再安排一個(gè)處理同一異常子句,因?yàn)榈诙€(gè)子句是永遠(yuǎn)執(zhí)行不到。通用catch子句應(yīng)用:21/4010.5異常和繼承定義一個(gè)稱為Excp基類,由它來(lái)打印錯(cuò)誤信息:classExcp{public:voidprint(stringmsg){cerr<<msg<<endl;}};再?gòu)脑摶惻缮鰞蓚€(gè)異常類:classstackExcp:publicExcp{...};//棧異常類基類classmathExcp:publicExcp{...};//數(shù)學(xué)庫(kù)異常基類深入派生出其它異常類:classpopOnEmpty:publicstackExcp{...};//??胀藯.惓lasspushOnFull:publicstackExcp{...};//棧滿壓棧異常classzeroOp:publicmathExcp{...};//數(shù)學(xué)庫(kù)零操作異常classdivideByZero:publicmathExcp{...};//數(shù)學(xué)庫(kù)被零除異常異常層次結(jié)構(gòu):在C++程序中,表示異常類通常被組成為一個(gè)組(即如在前面各節(jié)討論那樣)或者一個(gè)層次結(jié)構(gòu)。形成了三層結(jié)構(gòu)。22/4010.5異常和繼承在層次結(jié)構(gòu)下,異常拋出會(huì)有一些不一樣,以下做法是錯(cuò):if(full()){pushOnFullexcept(data);stackExcp*pse=&except;//pse指向類對(duì)象為pushOnFull

throw*pse;}//拋出異常對(duì)象類型為stackExcp 這里被創(chuàng)建異常類對(duì)象是stackExcp類類型,盡管pse指向一個(gè)實(shí)際類型為pushOnFull對(duì)象,但那是一個(gè)暫時(shí)對(duì)象,復(fù)制到異常對(duì)象存放區(qū)中時(shí)創(chuàng)建卻是stackExcp類異常對(duì)象。所以該異常不能被pushOnFull類型catch子句處理。層次結(jié)構(gòu)異常拋出:23/4010.5異常和繼承在處理類類型異常時(shí),catch子句排列次序是非常主要。catch(pushOnFull){...}//處理pushOnFull異常catch(stackExcp){...}//處理?xiàng)F渌惓atch(Excp){...}//處理普通異常派生類類型catch子句必須先出現(xiàn),以確保只有在沒有其它c(diǎn)atch子句適用時(shí),才會(huì)進(jìn)入基類類型catch子句。異常catch子句無(wú)須是與異常最匹配catch子句,而是最先匹配到catch子句,就是第一個(gè)碰到能夠處理該異常catch子句。所以在catch子句列表中最特化(匹配條件最嚴(yán)格)catch子句必須先出現(xiàn)。catch子句排列次序:24/4010.5異常和繼承類層次結(jié)構(gòu)異常一樣能夠重新拋出(rethrow),把一個(gè)異常傳遞給函數(shù)調(diào)用列表中更上層另一個(gè)catch子句:throw;類層次結(jié)構(gòu)下異常重新拋出:重新拋出異常仍是原來(lái)異常對(duì)象。假如程序中拋出了pushOnFull類類型異常,而它被基類catch子句處理,并在其中再次被拋出,那么這個(gè)異常仍是pushOnFull類異常,而不是其基類異常。25/4010.5異常和繼承在基類catch子句處理是異常對(duì)象基類子對(duì)象一份副本,該副本只在該catch子句中被訪問(wèn),重新拋出是原來(lái)異常對(duì)象。這個(gè)放在異常對(duì)象存放區(qū)中異常生命期應(yīng)該是在處理該異常一系列子句中最終一個(gè)退出時(shí)才結(jié)束,也就是直到這時(shí),才由異常類析構(gòu)函數(shù)來(lái)銷毀它。這一系列子句是由重新拋出聯(lián)絡(luò)起來(lái)?!纠?0.2】異常層次結(jié)構(gòu)中虛函數(shù)。為了調(diào)用派生類對(duì)象虛擬函數(shù),異常申明必須為一個(gè)指針或引用。

虛函數(shù)是類層次結(jié)構(gòu)中多態(tài)性基本伎倆,異常類層次結(jié)構(gòu)中也能夠定義虛擬函數(shù)。

26/4010.6

異常規(guī)范一個(gè)函數(shù)異常規(guī)范違例只能在運(yùn)行時(shí)才能被檢測(cè)出來(lái)。假如在運(yùn)行時(shí),函數(shù)拋出了一個(gè)沒有被列在它異常規(guī)范中異常時(shí)(而且函數(shù)中所拋出異常,沒有在該函數(shù)內(nèi)部處理)則系統(tǒng)調(diào)用C++標(biāo)準(zhǔn)庫(kù)中定義函數(shù)unexpected()。僅當(dāng)函數(shù)中所拋出異常,沒有在該函數(shù)內(nèi)部處理,而是逆調(diào)用鏈回溯尋找匹配catch子句時(shí)候,異常規(guī)范才起作用。假如異常規(guī)范為throw(),則表示不得拋出任何異常。異常規(guī)范(exceptionspecification)提供了一個(gè)方案,能夠伴隨函數(shù)申明列出該函數(shù)可能拋出異常,并確保該函數(shù)不會(huì)拋出任何其它類型異常,在stack類定義中可有:

voidPush(constT&data)throw(pushOnFull);TPop()throw(popOnEmpty);組員函數(shù)類內(nèi)申明和類外定義必須必須在兩處都有相同異常規(guī)范,一樣異常規(guī)范。異常規(guī)范引入:27/4010.6

異常規(guī)范classCBase{public:

virtualintfun1(int)throw();

virtualintfun2(int)throw(int);

virtualstringfun3()throw(int,string);};classCDerived:publicCBase{public:

intfun1(int)throw(int);

//錯(cuò)!異常規(guī)范不如throw()嚴(yán)格

intfun2(int)throw(int);//對(duì)!有相同異常規(guī)范

stringfun3()throw(string);}//對(duì)!異常規(guī)范比throw(int,string)更嚴(yán)格

虛函數(shù)中異常規(guī)范:派生類虛擬函數(shù)異常規(guī)范必須與基類虛函數(shù)異常一樣或更嚴(yán)格。因?yàn)楫?dāng)派生類虛函數(shù)被指向基類類型指針調(diào)用時(shí),確保不會(huì)違反基類組員函數(shù)異常規(guī)范。

28/4010.7C++標(biāo)準(zhǔn)庫(kù)異常類層次結(jié)構(gòu)(選讀)exception類接口以下:namespacestd{//注意在名字空間域std中

classexception{public:exception()throw();//默認(rèn)結(jié)構(gòu)函數(shù)

exception(constexception&)throw();//復(fù)制結(jié)構(gòu)函數(shù)

exception&operator=(constexception&)throw();

//復(fù)制賦值操作符

virtual~exception()throw();//析構(gòu)函數(shù)

virtual

constchar*what()

const

throw();

//返回一個(gè)C格調(diào)字符串,目標(biāo)是為拋出異常提供文本描述

};}C++標(biāo)準(zhǔn)庫(kù)中異常層次根類被稱為exception,定義在庫(kù)頭文件<exception>中29/4010.7C++標(biāo)準(zhǔn)庫(kù)異常類層次結(jié)構(gòu)(選讀)C++標(biāo)準(zhǔn)庫(kù)提供邏輯異常:invalid_argument異常,接收到一個(gè)無(wú)效實(shí)參,拋出該異常。out_of_range異常,收到一個(gè)不在預(yù)期范圍中實(shí)參,則拋出。length_error異常,匯報(bào)企圖產(chǎn)生“長(zhǎng)度值超出最大允許值”對(duì)象domain_error異常,用以匯報(bào)域錯(cuò)誤(domainerror)。C++標(biāo)準(zhǔn)庫(kù)提供運(yùn)行時(shí)異常:range_error異常,匯報(bào)內(nèi)部計(jì)算中范圍錯(cuò)誤。overflow_error異常,匯報(bào)算術(shù)溢犯錯(cuò)誤。underflow_error異常,匯報(bào)算術(shù)下溢錯(cuò)誤。以上三個(gè)異常是由runtime_error類派生。bad_alloc異常。當(dāng)new()操作符不能分配所要求存放區(qū)時(shí),會(huì)拋出該異常。它是由基類exception派生?!纠?0.3】為類模板Array重新定義下標(biāo)操作符[],假如索引值越界,它會(huì)拋出一個(gè)out_of_range類型異常。30/40第十章異常處理完謝謝!31/40[例10.1]堆棧異常處理template<typenameT>classpushOnFull{//棧滿異常申明

T_value;public: pushOnFull(Ti){_value=i;} Tvalue(){return_value;}

voidprint(){cerr<<"棧滿,"<<value()<<"未壓入棧"<<endl;}};template<typenameT>classpopOnEmpty{//??债惓I昝鱬ublic:

voidprint(){cerr<<"棧已空,無(wú)法出棧"<<endl;}};32/40[例10.1]堆棧異常處理template<typenameT>classStack{

inttop;//棧頂指針(下標(biāo))

T*elements;//動(dòng)態(tài)建立數(shù)值

intmaxSize;//棧最大允納元素個(gè)數(shù)public: Stack(int=20);//棧如不指定大小,設(shè)為20元素

~Stack(){delete[]elements;}

voidPush(constT&data)throw(pushOnFull<T>);//壓棧

TPop()throw(popOnEmpty);//彈出,top-- TGetElem(inti){returnelements[i];}//返回指定元素

voidMakeEmpty(){top=-1;}//清空棧

boolIsEmpty()const{returntop==-1;}//判???/p>

boolIsFull()const{returntop==maxSize-1;}//判棧滿

voidPrintStack();//輸出棧內(nèi)全部數(shù)據(jù)};33/40[例10.1]堆棧異常處理template<typenameT>voidStack<T>::Push(constT&data){

if(IsFull())throwpushOnFull<T>(data);//棧滿則拋出異常

elements[++top]=data;

//棧頂指針先加1,元素再進(jìn)棧,top是指向棧頂元素}template<typenameT>TStack<T>::Pop(){

if(IsEmpty())throwpopOnEmpty<T>();

//棧已空則不能退棧,拋出異常

returnelements[top--]; //返回棧頂元素,同時(shí)棧頂指針退1}34/40[例10.1]堆棧異常處理intmain(){

inta[9]={1,2,3,4,5,6,7,8,9},b[9]={0},i; Stack<int>istack(8);

try{

for(i=0;i<9;i++)istack.Push(a[i]);//到a[8]時(shí)棧滿,異常

istack.PrintStack(); }

catch(pushOnFull<int>&eObj){eObj.print();}

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'; cout<<endl;

return0;}35/40[例10.1_1]函數(shù)try塊(FunctiontryBlock)intmain()try{

inta[9]={1,2,3,4,5,6,7,8,9},b[9]={0},i; Stack<int>istack(8);

for(i=0;i<9;i++)istack.Push(a[i]);//到a[8]時(shí)棧滿,異常

istack.PrintStack();

for(i=0;i<9;i++)b[i]=istack.Pop();

for(i=0;i<9;i++)cout<<b[i]<<'\t';//發(fā)生異常后不會(huì)執(zhí)行

cout<<endl;

return0;}catch(pushOnFull<int>&eObj){ eObj.print();return1;}catch(popOnEmpty<int>&eObj){ eObj.print();return2;}36/40[例10.2]異常層次結(jié)構(gòu)中虛函數(shù)classExcp{public:

virtualvoidprint(){cerr<<"發(fā)生異常"<<endl;}};classstackExcp:publicExcp{public:

virtualvoidprint(){cerr<<"棧發(fā)生異常"<<endl;}};classpushOnFull:publicstackExcp{public:

virtualvoidprint(){cerr<<"棧滿,不能壓棧"<<en

溫馨提示

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

評(píng)論

0/150

提交評(píng)論