c基礎(chǔ)知識異常處理機(jī)制實(shí)用_第1頁
c基礎(chǔ)知識異常處理機(jī)制實(shí)用_第2頁
c基礎(chǔ)知識異常處理機(jī)制實(shí)用_第3頁
c基礎(chǔ)知識異常處理機(jī)制實(shí)用_第4頁
c基礎(chǔ)知識異常處理機(jī)制實(shí)用_第5頁
已閱讀5頁,還剩34頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

會計學(xué)1c基礎(chǔ)知識異常處理機(jī)制實(shí)用10.1

異常的概念

異常概念的引入:

異常(exception)是程序可能檢測到的,運(yùn)行時不正常的情況,如存儲空間耗盡、數(shù)組越界、被0除等等??梢灶A(yù)見可能發(fā)生在什么地方,但是無法確知怎樣發(fā)生和何時發(fā)生。特別在一個大型的程序(軟件)中,程序各部分是由不同的小組編寫的,它們由公共接口連起來,錯誤可能就發(fā)生在相互的配合上,也可能發(fā)生在事先根本想不到的個別的條件組合上。C++提供了一些內(nèi)置的語言特性來產(chǎn)生(raise)或拋出(throw)異常,用以通知“異常已經(jīng)發(fā)生”,然后由預(yù)先安排的程序段來捕獲(catch)異常,并對它進(jìn)行處理。這種機(jī)制可以在C++程序的兩個無關(guān)(往往是獨(dú)立開發(fā))的部分進(jìn)行“異?!蓖ㄐ?。由程序某一部分引發(fā)了另一部分的異常,這一異??苫氐揭甬惓5牟糠秩ヌ幚恚嬷绦蚝瘮?shù)的調(diào)用鏈)。第1頁/共39頁10.2

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

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

//注意加了括號,是構(gòu)造一個無名對象

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

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

returnelements[top--];}注意pushOnFull是類,C++要求拋出的必須是對象,所以必須有“()”,即調(diào)用構(gòu)造函數(shù)建立一個對象。異常與異常拋出:以棧為例,異常類聲明如下:classpopOnEmpty{...};//??债惓lasspushOnFull{...};//棧滿異常第2頁/共39頁10.2

異常處理的機(jī)制throw表達(dá)式拋出異常為異常處理的第一步。在堆棧的壓棧和出棧操作中發(fā)生錯誤而拋出的異常,理所當(dāng)然地應(yīng)由調(diào)用堆棧的程序來處理。異常并非總是類對象,throw表達(dá)式也可以拋出任何類型的對象,如枚舉、整數(shù)等等。但最常用的是類對象。在C++中異常拋出與異常處理之間有一整套程序設(shè)計的機(jī)制。首先采用關(guān)鍵字try,構(gòu)成一個try塊(tryblock),它包含了拋出異常的語句。當(dāng)然也可以是包含了這樣的調(diào)用語句,該語句所調(diào)用的函數(shù)中有能夠拋出異常的語句。異常處理機(jī)制:第3頁/共39頁10.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í)例:第4頁/共39頁10.2

異常處理的機(jī)制由catch字句捕獲并處理異常是第二步。注意與catch語句分別匹配的是在壓棧和出棧成員函數(shù)模板中的throw語句,一個拋出pushOnFull類的無名對象,另一個拋出popOnEmpty類的無名對象。在編制程序時有一條慣例:把正常執(zhí)行的程序與異常處理兩部分分隔開來,這樣使代碼更易于跟隨和維護(hù)。在上例中,我們可以把兩個try塊合成一個,而把兩個catch子句都放在函數(shù)最后。

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

第5頁/共39頁10.2

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

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

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

catch子句說明:當(dāng)try塊中的語句拋出異常時,系統(tǒng)通過查看跟在其后的catch子句列表,來查找可處理該異常的catch子句。第7頁/共39頁10.3棧展開與異常捕獲對應(yīng)在throw表達(dá)式中,構(gòu)造拋出對象也要有實(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)用構(gòu)造函數(shù)時的實(shí)參。catch子句異常聲明探討:異常聲明中可以是一個對象聲明。以棧為例。當(dāng)棧滿時,要求在異常對象中保存不能被壓入到棧中的值,pushOnFull類可定義如下:第8頁/共39頁10.3棧展開與異常捕獲

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

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

return1;}在catch子句的異常聲明中聲明了對象eObj,用它來調(diào)用pushOnFull類的對象成員函數(shù)value()。異常對象是在拋出點(diǎn)被創(chuàng)建,與catch子句是否顯式要求創(chuàng)建一個異常對象無關(guān),該對象總是存在,在catch子句中只是為了調(diào)用異常處理對象的成員函數(shù)才聲明為對象,不用類。*catch子句異常聲明中采用對象只是一種形式。甚至異常并非一個類對象時,也可以用同樣的格式,比如異常為一枚舉量,這時就等效于按值傳遞,而不是調(diào)用類對象的公有成員。第9頁/共39頁10.3棧展開與異常捕獲catch子句的異常聲明與函數(shù)參數(shù)聲明類似,可以是按值傳送,也可以是按引用傳遞。對大型類對象減少不必要的復(fù)制是很有意義的,所以對于類類型的異常,其異常聲明最好也是被聲明為引用。如:catch(pushOnFull<T>&eObj){cerr<<”棧滿”<<eObj.value()<<”未壓?!?lt;<endl;

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

【例10.1】包含棧滿或空異常的完整的程序。第10頁/共39頁10.3棧展開與異常捕獲把程序的正常處理代碼和異常處理代碼分離的最清楚的方法是定義函數(shù)try塊(FunctiontryBlock)。這種方法是把整個函數(shù)包括在try塊中。

一個函數(shù)try塊把一組catch子句同一個函數(shù)體相關(guān)聯(lián)。如果函數(shù)體中的語句拋出一個異常,則考慮跟在函數(shù)體后面的處理代碼來處理該異常。函數(shù)try塊對構(gòu)造函數(shù)尤其有用?!纠?0.1_1】定義函數(shù)try塊(FunctiontryBlock)。

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

第12頁/共39頁10.3棧展開與異常捕獲

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

棧展開:因發(fā)生異常而逐步退出復(fù)合語句和函數(shù)定義的過程,被稱為棧展開(stackunwinding)。這是異常處理的核心技術(shù)。異常對程序的影響通常不僅是在發(fā)生異常的那個局部范圍中,而且可能逆調(diào)用鏈而上,甚至整個任務(wù)。因此,異常處理應(yīng)該在其對程序影響的終結(jié)處進(jìn)行,甚至是在調(diào)用該任務(wù)的菜單處進(jìn)行。第13頁/共39頁10.3棧展開與異常捕獲

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

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

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

rethrow表達(dá)式仍為:throw;

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

異常的重新拋出與連續(xù)處理:當(dāng)catch語句捕獲一個異常后,可能不能完全處理異常,完成某些操作后,該異常必須由函數(shù)鏈中更上級的函數(shù)來處理,這時catch子句可以重新拋出(rethrow)該異常,把異常傳遞給函數(shù)調(diào)用鏈中更上級的另一個catch子句,由它進(jìn)行進(jìn)一步處理。第17頁/共39頁10.4異常的重新拋出和catch_all子句(選讀)通用catch子句(catch_all):catch(...){代碼*/}

任何異常都可以進(jìn)入這個catch子句。這里的三個點(diǎn)稱為省略號?;ɡㄌ栔械膹?fù)合語句用來執(zhí)行指定操作。異常發(fā)生后按棧展開(stackunwinding)退出,動態(tài)分配的非類對象資源不會自動釋放的,通常在catch_all子句中釋放。voidfun1(){

int*res;res=newint[100];//定義一個資源對象

try{//代碼包括使用資源res和某些可能引起異常拋出的操作

}//異??赡苡卸喾N

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

delete[]res;//釋放資源對象res

throw;}//重新拋出異常

delete[]res;}//正常退出前釋放資源對象res;第18頁/共39頁10.4異常的重新拋出和catch_all子句(選讀)

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

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

throw*pse;}//拋出的異常對象的類型為stackExcp 這里被創(chuàng)建的異常類對象是stackExcp類類型,盡管pse指向一個實(shí)際類型為pushOnFull的對象,但那是一個臨時對象,復(fù)制到異常對象的存儲區(qū)中時創(chuàng)建的卻是stackExcp類的異常對象。所以該異常不能被pushOnFull類型的catch子句處理。層次結(jié)構(gòu)異常的拋出:第21頁/共39頁10.5異常和繼承在處理類類型異常時,catch子句的排列順序是非常重要的。catch(pushOnFull){...}//處理pushOnFull異常catch(stackExcp){...}//處理?xiàng)5钠渌惓atch(Excp){...}//處理一般異常派生類類型的catch子句必須先出現(xiàn),以確保只有在沒有其他catch子句適用時,才會進(jìn)入基類類型的catch子句。異常catch子句不必是與異常最匹配的catch子句,而是最先匹配到的catch子句,就是第一個遇到的可以處理該異常的catch子句。所以在catch子句列表中最特化的(匹配條件最嚴(yán)格的)catch子句必須先出現(xiàn)。catch子句的排列順序:第22頁/共39頁10.5異常和繼承類層次結(jié)構(gòu)的異常同樣可以重新拋出(rethrow),把一個異常傳遞給函數(shù)調(diào)用列表中更上層的另一個catch子句:throw;類層次結(jié)構(gòu)下的異常重新拋出:重新拋出的異常仍是原來的異常對象。如果程序中拋出了pushOnFull類類型的異常,而它被基類的catch子句處理,并在其中再次被拋出,那么這個異常仍是pushOnFull類的異常,而不是其基類的異常。第23頁/共39頁10.5異常和繼承在基類catch子句處理的是異常對象的基類子對象的一份副本,該副本只在該catch子句中被訪問,重新拋出的是原來的異常對象。這個放在異常對象存儲區(qū)中的異常的生命期應(yīng)該是在處理該異常的一系列的子句中最后一個退出時才結(jié)束,也就是直到這時,才由異常類的析構(gòu)函數(shù)來銷毀它。這一系列的子句是由重新拋出聯(lián)系起來的。【例10.2】異常層次結(jié)構(gòu)中的虛函數(shù)。為了調(diào)用派生類對象的虛擬函數(shù),異常聲明必須為一個指針或引用。

虛函數(shù)是類層次結(jié)構(gòu)中多態(tài)性的基本手段,異常類層次結(jié)構(gòu)中也可以定義虛擬函數(shù)。

第24頁/共39頁10.6

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

voidPush(constT&data)throw(pushOnFull);TPop()throw(popOnEmpty);成員函數(shù)類內(nèi)聲明和類外定義必須必須在兩處都有相同的異常規(guī)范,同樣的異常規(guī)范。異常規(guī)范的引入:第25頁/共39頁10.6

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

virtualintfun1(int)throw();

virtualintfun2(int)throw(int);

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

intfun1(int)throw(int);

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

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

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

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

第26頁/共39頁10.7C++標(biāo)準(zhǔn)庫的異常類層次結(jié)構(gòu)(選讀)exception類的接口如下:namespacestd{//注意在名字空間域std中

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

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

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

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

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

virtual

constchar*what()

const

throw();

//返回一個C風(fēng)格的字符串,目的是為拋出的異常提供文本描述

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

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

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

voidprint(){cerr<<"棧已空,無法出棧"<<endl;}};第30頁/共39頁[例10.1]堆棧異常處理template<typenameT>classStack{

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

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

intmaxSize;//棧最大允納的元素個數(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ù)};第31頁/共39頁[例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--]; //返回棧頂元素,同時棧頂指針退1}第32頁/共39頁[例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]時棧滿,異常

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;}第33頁/共39頁[例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]時棧滿,異常

istack.PrintStack();

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

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

cout<<endl;

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

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

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

virtualvoidprint(){cerr<<"棧滿,不能壓棧"<<endl;}};classpopOnEmpty:publ

溫馨提示

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

最新文檔

評論

0/150

提交評論