版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
1、C+之異常處理一個好的程序應該能對多種不同的特殊情況,做出不同的反應,對于突發(fā)情況也應有對應的處理方法。我們在編程時應考慮到各種突發(fā)情況,并在程序中給出解決方案,使程序的健壯性增強。假設有一個司機從A地開車前往B地。若在某處有一岔路口,一般選擇左邊,路程會近一些。但當司機選擇左邊,將車開到途中時發(fā)現(xiàn)正在修路(突發(fā)情況),無法通過。這時,司機就會掉頭回到剛才的岔路口處,重新選擇右邊的路,繼續(xù)前進。 我們所編的程序也應該像這樣,有一定的智能化的設計。這就要求在編寫程序時,應該試著確定程序可能出現(xiàn)的錯運,然后加入處理錯誤的代碼。例如:當程序執(zhí)行文件I0操作時,應測試文件打開以及讀寫操作是否成功,并且
2、在出現(xiàn)錯誤時做出正確的反應。隨著程序復雜性的增加,為處理錯誤而必須包括在程序中代碼的復雜性也相應地增加了。為使程序更易于測試和處理錯誤,C+實現(xiàn)了異常處理機制。一、異常概念 1異常的概念程序的錯誤,一種是編譯錯誤,即語法錯誤。如果使用了錯誤的語法、函數(shù)、結(jié)構(gòu)和類,程序就無法被生成運行代碼。另一種是在運行時發(fā)生的錯誤,它分為不可預料的邏輯錯誤和可以預料的運行異常。運行異常,可以預料,但不能避免,它是由系統(tǒng)運行環(huán)境造成的。如,內(nèi)存空間不足,而程序運行中提出內(nèi)存分配申請時,得不到滿足,就會發(fā)生異常:#include<fstream.h>/void f(char *str)ifstream
3、 source(str); 打開str串中的文件if(sourcefail()打不開cerr <<"Error opening the file:"<<str <<endl; exit(1); 退出程序 /當程序?qū)ξ募虿婚_時,程序會打印提示信息,并由exit(1)函數(shù)退出。這樣就不至于會因為文件打不開而導致整個程序在運行過程中停滯或錯亂。2異常的基本思想 在小型程序中,一旦發(fā)生異常,一般是將程序立即中斷運行,從而無條件釋放所有資源。對于大型程序來說,運行中一旦發(fā)生異常,應該允許恢復和繼續(xù)運行。恢復的過程就是把產(chǎn)生異常所造成的惡劣影響去掉
4、,中間可能要涉及一系列的函數(shù)調(diào)用鏈的退棧,對象的析構(gòu),資源的釋放等。繼續(xù)運行就是異常處理之后,在緊接著異常處理的代碼區(qū)域中繼續(xù)運行。在C+中,異常是指從發(fā)生問題的代碼區(qū)域傳遞到處理問題的代碼區(qū)域的一個對象。見圖 :發(fā)生異常的地方在函數(shù)k()中,處理異常的地方在其上層函數(shù)f()中,處理異常后,函數(shù)k()和g()都退棧,然后程序在函數(shù)f()中繼續(xù)運行。如果不用異常處理機制,在程序中單純地嵌入錯誤處理語句,要實現(xiàn)這一目的是艱難的。 異常的基本思想是:(1)實際的資源分配(如內(nèi)存申請或文件打開)通常在程序的低層進行,如圖中的k()。(2)當操作失敗、無法分配內(nèi)存或無法打開一個文件時在邏輯上如何進行處理
5、通常是在程序的高層,如圖中的f(),中間還可能有與用戶的對話。 (3)異常為從分配資源的代碼轉(zhuǎn)向處理錯誤狀態(tài)的代碼提供了一種表達方式。如果還存在中間層次的函數(shù),如圖中的g(),則為它們釋放所分配的內(nèi)存提供了機會,但這并不包括用于傳遞錯誤狀態(tài)信息的代碼。 從中可以看出,C什異常處理的目的,是在異常發(fā)生時,盡可能地減小破壞,周密地善后,而不去影響其它部分程序的運行。-這在大型程序中是非常必要的。例如對于以前所講的程序調(diào)用關系,如處理文件打開失敗異常的方法,那么,異常只能在發(fā)生的函數(shù)k()中進行處理,無法直接傳遞到函數(shù)f()中,而且調(diào)用鏈中的函數(shù)g()的善后處理也十分困難。二、異常的實現(xiàn)使用異常的步
6、驟是:(1)定義異常(try語句塊) 將那些可能產(chǎn)生錯誤的語句框定在try語句中;(2)定義異常處理(catch語句塊)將異常處理的語句放在catch塊中,以便異常被傳遞過來時就處理它;(3)拋擲異常(throw語句)檢測是否產(chǎn)生異常,若產(chǎn)生異常,則拋擲異常。例如,下面的程序,設置了防備文件打不開的異常:例題1#include <fstream.h>#include <iostream.h>#include <stdlib.h>void main(int argc,char *argv) ifstream source(argv1); /打開文件 char
7、line128;try if(source.fail() /如果打開失敗throw argv1;catch (char *s) cout<<"error opening the file"<<s<<endl; exit(1); while(!source.eof() source.getline(line,sizeof(line);cout<<line<<endl; source.close();運行結(jié)果:假定C盤中沒有abc.txt文件,有xyz.txt文件,內(nèi)容為: How are you? Fine!兩行語句
8、,則運行結(jié)果為:在c:>提示符后輸入命令 ch10_1 abc.txt屏幕顯示結(jié)果為: error opening the file abc.txt若輸入命令 ch10_1 xyz.txt則屏幕顯示結(jié)果為: How are you? Fine!例題2:一個除零異常:#include<iostream.h>double Div(double,double);void main()try cout<<"7.3/2.0="<<Div(7.3,2.0)<<endl; cout<<"7.3/0.0="
9、;<<Div(7.3,0.0)<<endl; cout<<"7.3/1.0="<<Div(7.3,1.0)<<endl;catch(double)cout<<"except of deviding zero!n" cout<<"That is ok.n"double Div(double a,double b) if(b=0.0) throw b; return a/b; 運行結(jié)果為:7.3/2.0=3.65except of deviding zer
10、o!That is ok.三、 異常處理機制在處理程序和語句之間的相互作用使異常在大型應用程序中變得復雜。通常人們希望拋擲被及時捕獲,以避免程序突然終止。此外,跟蹤拋擲很重要,因為捕獲確定該程序的后繼進展。例如,拋擲和捕獲可以用來重新開始程序內(nèi)的一個過程,或者從應用程序的一部分跳到另一部分,或者回到菜單。例如,項目的代碼說明了異常處理機制。void f() try g(); catch(Range) / catch (Size) / catch ()void g()h();void h()try h1();catch(Size)/.throw 10;catch(Matherr)/.void h
11、1()/.throw(Size);try/.throw Range;h2();h3();catch(Size)/.throw; void h2()/.throw Matherr;void h3()/.throw Size;函數(shù)f()中的catch(.)塊,參數(shù)為省略號,定義一個"默認"的異常處理程序。通常這個處理程序應在所有異常處理塊的最后,因為它與任何throw都匹配,目的是為避免定義的異常處理程序沒能捕獲拋擲的異常而使程序運行終止。函數(shù)h()中的catch(Size)塊,包含有一個拋擲異常語句throw 10,當實際執(zhí)行這條語句時,將沿著調(diào)用鏈向上傳遞被函數(shù)f()中的c
12、atch(.)所捕獲。如果沒有f()中的catch(.),那么,異常將被系統(tǒng)的terminate()函數(shù)調(diào)用,后者按常規(guī)再調(diào)用abort()。函數(shù)h1()中的拋擲throw Size,由于不在本函數(shù)的try塊中,所以只能沿函數(shù)調(diào)用鏈向上傳遞,結(jié)果被h()中的catch(Size)捕獲。函數(shù)h1()中的拋擲throw Range,在try塊中,所以首先匹配try塊后的異常處理程序,可是沒有被捕獲,因而它又沿函數(shù)調(diào)用鏈向上,在函數(shù)f()中,catch(Range)塊終于捕獲了該拋擲。函數(shù)h1()中的catch(Size)塊,包含一個拋擲throw,沒有帶參數(shù)類型,它表示將捕獲到的異常對象重新拋擲出
13、去,于是,它將沿函數(shù)調(diào)用鏈向上傳遞,在h()中的catch(Size)塊,捕獲了該拋擲。函數(shù)h2()中的拋擲throw Matherr,首先傳遞給h1()中的catch塊組,但未能被捕獲,然后繼續(xù)沿調(diào)用鏈向上,在h()中的catch(Matherr)塊,捕獲了該拋擲。函數(shù)h3()中的拋擲throw Size,向上傳遞給h1()中的catch塊組,被catch(Size)塊捕獲。四、 使用異常的方法可以把多個異常組成族系。構(gòu)成異常族系的一些實力又數(shù)學錯誤異常族系和文件處理錯誤異常族系。在C+代碼中把異常組在一起有兩種方式:異常枚舉族系和異常派生層次結(jié)構(gòu)。例如,下面的代碼是一個異常枚舉族系的例子:
14、enmu FileErrorsnonExist,wrongformat,diakSeekError,.;int f() try /. throw wrongFormat;catch(FileErrors fe) switch(fe) case nonExist: /.case wrongFormat: /. case diskSeekError: /./.在try塊中有一個throw,它拋擲一個FileError枚舉中的常量。這個拋擲可被catch(FileErrors)塊捕獲到,接著后者執(zhí)行一個switch,對照情況列表,匹配捕獲到的枚舉常量值。上面的異常族系也可按異常派生層次結(jié)構(gòu)來實現(xiàn),如
15、下例所示:class FileErrors;class NonExist:public FileErrors;class WrongFormat:public FileErrors;class DiskSeekError:public FileErrors;int f() try /. throw WrongFormat;catch(NonExist) /.catch(DiskSeekError) /.catch(FileErrors) /./.上面的各異常處理程序塊定義了針對類NonExist和DiskSeekError的派生異常類對象,針對FileErrors的異常處理,既捕獲FileEr
16、rors類對象,也捕獲WrongFormat對象。異常捕獲的規(guī)則除了前面所說的,必須嚴格匹配數(shù)據(jù)類型外,對于類的派生,下列情況可以捕獲異常:(1) 異常處理的數(shù)據(jù)類型是公有基類,拋擲異常的數(shù)據(jù)類型是派生類;(2) 異常處理的數(shù)據(jù)類型是指向公有基類的指針,拋擲異常的數(shù)據(jù)類型是指向派生類的指針。 對于派生層次結(jié)構(gòu)的異常處理,catch塊組中的順序是重要的。因為"catch(基類)"總能夠捕獲"throw派生類對象"。所以"catch(基類)"塊總是放在"catch(派生類)"塊的后面,以避免"catch(派生
17、類)"永遠不能捕獲異常。五、 異常的再提出(rethrowing) 有時候會發(fā)生一個異常處理句柄接收了一個異常卻發(fā)現(xiàn)不能處理這個異常的情況。這時,這個異??梢员辉偬岢鲆员阌谄渌浔軌蚋玫奶幚?。異常的再提出可以通過一個空的throw表達語句來實現(xiàn)。但是,這種表達語句只能出現(xiàn)于一個異常處理句柄中。例如, void f() try showWindow(); /提出CoDialogException類異常 catch (CoWindowException& WinExc) WinExc.repaint(); throw; /異常再提出 void g() try f(); cat
18、ch (CoDialogException& DialogExc) /*異常處理語句*/ catch (CoWindowException& WindowExc) /*異常處理語句*/ 上述例子中,盡管CoDialogException類異常是由函數(shù)f()中的CoWindowException類處理句柄再提出的,但是它仍然由函數(shù)g()中的CoDialogException類異常處理句柄來處理。 此外,任何異常都可以通過一種特殊的接收方式catch(.)來接收和處理。例如下面例子中的f()函數(shù)可以接收任何異常并再提出。 void f() try showWindow(); cat
19、ch(.) /接收任何異常 /某些處理語句 throw; 值得注意的是,異常的再提出并不對異常對象進行進一步的拷貝。 #include <iostream> #include <string> using namespace std; enum SUCCESS, FAILURE; class File public: File (const char *) public:
20、0;bool IsValid() const return false; public: int OpenNew() const return FAILURE; class Exception /*.*/; /general base class for exceptions class FileException: public Excep
21、tion public: FileException(const char *p) : s(p) public: const char * Error() const return s.c_str(); private: string s; void func(File& ); int main()
22、 try /outer try File f ("db.dat"); func(f); / 1 catch(.) / 7 /this handler will catch the re-thrown exception; /note: the same exception type is
23、60;required cout<<"re-thrown exception caught" return 0; void func(File & f) try /inner try if (f.IsValid() = false ) throw FileException("db.dat"
24、;); / 2 catch(FileException &fe) / 3 /first chance to cope with the exception cout<<"invalid file specification" <<fe.Error()<<endl; if (f.OpenNew() !=
25、;SUCCESS) (5) /re-throw the original exception and let a higher handler deal with it throw; / 6 在上面的例子中,函數(shù)func()在main()中的try block里被調(diào)用(1)。第二個在func()中的try block拋出一個FileException類型的異常(2)。這個異常被fun
26、c()內(nèi)的catch block所捕獲(3)。那個catch block試圖通過打開一個新文件進行補救,但是失敗了(5),并且FileException異常被重新拋出(6)。最終,那個重新拋出的異常被main()中的catch()所捕獲(7)。 六. 在異常對象中攜帶更多的信息 異常對象如同其它類對象一樣可以攜帶信息。所以一個異常對象可以被用來將一些有用信息從提出點攜帶到接收處理點。這些信息可以是當程序在運行過程中出現(xiàn)非正常情況時程序使用者想要知道的。例如一個程序使用者可能想知道一個矢量的下標,當這個矢量下標超限時。 class CoVector public:
27、 CoVector(int); class Range; int& operator (int i); protected: int* pInt_; int theSize; ; class CoVector:Range public: CoVector:Range(int); int index_; ; CoVector:Range:Range(int i):index_(i) /* . */ int& CoVector:operator(int i) if (0 <= i && i << theSize_) return pInt_i; t
28、hrow Range(i); void f(const CoVector& v) try int temp = v169; catch (const CoVector:Range& r) cout << "bad index = " << r.index_ << endl; 實際上,catch后面括弧中的表達語句實際上類似于函數(shù)的參數(shù)定義。 七、 句柄的次序 異常處理句柄有先后次序之分。因為一個派生(derived)異常類對象可以被幾個句柄接收,所以在排列異常處理句柄順序時應該特別小心。另外,一個類型嚴格匹配的處理句柄并不
29、比一個需要類型轉(zhuǎn)換的處理句柄更有優(yōu)先權(quán)。例如下面的例子就很糟糕。 class CoWindow /* . */ ; class CoButton:public CoWindow /* . */ ; void f(int v) typedef void (*PCF)(const char*); try if (v) throw &v; /其它表達語句 catch (void * pVoid) /* . */ catch (PCF pFunction) /* . */ catch (const CoWindow& win) /* . */ catch (const CoButton
30、& button) /* . */ catch (.) /* . */ return; 在上面例子中,(void *)處理句柄不可能允許它后面的PCF處理句柄被調(diào)用。類似的,因為CoWindow類處理句柄將會接收任何CoWindow類及它的衍生類對象,所以CoButton類的處理句柄也不會被調(diào)用。依賴于你所使用的編譯器,有的編譯器可能在編譯時警告你一個從類B派生來的類D句柄放在類B句柄后面。但是,如果一個接收任何異常的句柄catch(.)不是最后一個句柄,編譯器會給出編譯錯誤。派生類組織異常;Class Matherr;Class Overflow: public Matherr;Cl
31、ass Underflow: public Matherr;Class:Zerodivide:public Matherr;Try Cath (Overflow) Cath (Uunderflow) Cath (Zerodivideflow) Cath (Matherr) 八、 異常提出過程中的對象構(gòu)造和析構(gòu) 當一個程序由于異常而中斷時,所有的從try開始構(gòu)造的自動變量類的對象都會被清除、釋放。這種調(diào)用自動變量類的析構(gòu)函數(shù)的過程稱為堆棧清除(stack unwinding)。下面給出了一個實例。 class CoClass public: int v_; CoClass(int v = 0)
32、: v_(v) cout << "CoClass(int): " << v_ << endl; CoClass() cout << "CoClass(): " << v_ << endl; ; class CoError public: int v_; CoError(int v = 0):v_(v) cout << "CoError(int): " << v_ << endl; CoError(const CoError&am
33、p; ve):v_(ve.v_) cout << "CoError(const CoError&): " << v_ << endl; CoError() cout << "CoError(): " << v_ << endl; ; int f(int v) if (v = 13) CoClass vc(0); throw CoError(v); return v; int main() try CoClass vc(169); f(13); catch (const CoE
34、rror& e) cout << "Caught : " << e.v_ << endl; return 0; 這個例子給出了下面輸出結(jié)果。 當 catch( const CoError e) 時CoClass(int): 169 CoClass(int): 0 CoError(int): 13 CoError(const CoError&): 13 CoClass(): 0 CoClass(): 169 Caught : 13 CoError(): 13 CoError(): 13 當 catch( const CoEr
35、ror & e) 時CoClass(int): 169 CoClass(int): 0 CoError(int): 13 CoClass(): 0 CoClass(): 169 Caught : 13 CoError(): 13 當一個異常在一個類對象的構(gòu)造過程中被提出時,如果這個類對象中包含了其它成員類對象,那么那些在異常提出前完成了構(gòu)造的成員類對象的析構(gòu)函數(shù)會被調(diào)用來清除已構(gòu)造了的成員對象。而那些沒有完成構(gòu)造的成員類對象的析構(gòu)函數(shù)不會被調(diào)用。例如,如果在構(gòu)造一個類對象的數(shù)組過程中一個異常被提出,那么只有那些完成了構(gòu)造的對象的析構(gòu)函數(shù)才被調(diào)用來進行堆棧清除。 接收一個析構(gòu)函數(shù)提出的異
36、常也是可能的。將調(diào)用析構(gòu)函數(shù)的函數(shù)放在try后面的程序塊中,并且提供適當?shù)念愋途浔涂梢粤恕?九、 函數(shù)的異常規(guī)范 一個函數(shù)的參數(shù)串稱之為這個函數(shù)的簽名(signature),因為它經(jīng)常被用來區(qū)別一個函數(shù)實體。一個函數(shù)由四個部分組成。(1)返回類型。(2)函數(shù)名。(3)函數(shù)簽名。(4)函數(shù)體。前三個部分常稱作為函數(shù)原型(function prototype).函數(shù)原型提供給了編譯器關于這個函數(shù)的類型信息。編譯器通過這些信息進行類型診斷。通常一個函數(shù)的使用者只需要知道這個函數(shù)原型就可以了。但是如果使用者想寫這個函數(shù)所提出的所有異常句柄,那么這個使用者就需要知道這些異常類型。 要解決這個問題,一個
37、函數(shù)原型或者定義(definition)可以包括異常規(guī)范(exception specifications)。異常規(guī)范出現(xiàn)在一個函數(shù)定義后面。它列出了這個函數(shù)可以直接或間接提出的異常。例如下面給出了一些函數(shù)的原型 void f() throw(v1, v2, v3); void g(); void h() throw(); void e() throw(WClass *); f()的定義表明了這個函數(shù)可以提出類型v1,v2和v3,以及它們的派生類型。如果函數(shù)f()提出除此以外的其它異常,程序在運行中會產(chǎn)生一個運行錯誤。函數(shù)g()的定義沒有包含異常規(guī)范。這意味著它可以提出任何異常。而函數(shù)h()則
38、不能提出任何異常。函數(shù)e()可以提出WClass類的指針型異常,或者由WClass派生來的類指針異常。 一個函數(shù)后面的異常規(guī)范并不屬于這個函數(shù)指針中的一部分。然而當一個指向函數(shù)的指針賦值給指向另一個函數(shù)的指針時,只有在被賦值的指針函數(shù)包含了賦值指針函數(shù)的異常時才允許。例如 void (*pf1)(); /沒有異常規(guī)范 void (*pf2)() throw(int); /只能提出整型異常 void f() pf1 = pf2; /可以,pf1要求比較寬松 pf2 = pf1; /錯誤,pf2要求更嚴格 下面函數(shù) void f() throw(v1,v2,v3) SomeAction(); 相當
39、于 void f() try SomeAction(); catch(v1 v) throw; /在提出 catch(v2 v) throw; /在提出 catch(v3 v) throw; /在提出 catch(.) unexpected(); /定義在頭文件<exception>中 當一個函數(shù)提出的異常沒有包括在這個函數(shù)的異常規(guī)范中時,程序會自動調(diào)用函數(shù)unexpected()來處理這個異常。函數(shù)unexpected()的缺省行為是調(diào)用使用者通過set_unexpected()函數(shù)注冊的函數(shù)。假如沒有任何函數(shù)通過set_unexcepted()來注冊,函數(shù)unexpected(
40、)則調(diào)用函數(shù)terminate()。這三個函數(shù)的原型如下。 void unexpected(); typedef void (*unexpected_handler)(); unexpected_handler set_unexpected(unexpected_handler) throw(); void terminate(); 函數(shù)set_unexpected()的返回值是前一次通過set_unexpected()注冊的函數(shù)指針。 函數(shù)terminate()可以通過unexpected()來調(diào)用,或者當找不到一個異常句柄時程序自動調(diào)用。terminate()函數(shù)的缺省行為是調(diào)用函數(shù)abo
41、rt()。這個缺省函數(shù)即刻中止程序運行。你可以改變當一個異常沒有出現(xiàn)于函數(shù)的異常規(guī)范中時的程序中止方式。如果你不想你的程序通過調(diào)用abort()來中止,你可以定義另外一個函數(shù)來替代它。這樣的函數(shù)通過set_terminate()函數(shù)來注冊并由terminate()調(diào)用。函數(shù)set_terminate()的定義如下 typedef void (*terminate_handler)(); terminate_handler set_terminate(terminate_handler) throw(); 這個函數(shù)的返回值是前一次通過函數(shù)set_terminate()來注冊的函數(shù)指針。 頭文件&
42、lt;exception>定義了處理異常的函數(shù),類及其數(shù)據(jù)成員和成員函數(shù)。 十、 具有異常規(guī)范的虛擬函數(shù) 一個虛擬函數(shù)也可以定義異常規(guī)范。但是,一個子類中的虛擬函數(shù)提出的異常不能比父類中的虛擬函數(shù)提出的異常多。也就是說,一個子類中的虛擬函數(shù)規(guī)范不能比父類中的虛擬函數(shù)規(guī)范更寬松。而一個子類中的虛擬函數(shù)提出的異常比父類中的虛擬函數(shù)提出的異常少則是允許的。例如 class CoWindow public: virtual void show() throw(int); virtual void getFocus() throw(int, char); ; class CoDialogBox:p
43、ublic CoWindow public: virtual void show() throw(int, char); /錯誤,異常規(guī)范較寬松 virtual void getFocus() throw(int); /可以,異常規(guī)范更嚴歷 ; 編譯器針對CoDialog:show()會給出編譯錯誤,因為在運行時這個函數(shù)既可以提出int類型異常也可以提出char類型異常。而在父類定義中,這個虛擬函數(shù)只能提出int類型異常。另一方面,CoDialog:getFocus()是允許的,因為它的規(guī)范比父類中的虛擬函數(shù)的異常規(guī)范要求更嚴歷。 例題:下面我們用示例演示一下異常處理: 1 #inc
44、lude "stdafx.h" 2 #include <iostream> 3 template <typename T> 5 T Div(T x,T y) if(y=0) throw y;/拋出異常 return x/y; int main() int x=5,y=0;double x1=5.5,y1=0.0; try
45、 /被檢查的語句 std:cout<<x<<"/"<<y<<"="<<Div(x,y)<<std:endl; std:cout<<x1<<"/"<<y1<<"="<<Div(x1,y1)<<std:
46、endl; catch(int)/異常類型 std:cout<<"除數(shù)為0,計算錯誤!"<<std:endl;/異常處理語句 catch(double)/異常類型 &
47、#160; std:cout<<"除數(shù)為0.0,計算錯誤!"<<std:endl;/異常處理語句29 return 0; 結(jié)果: 看了上述的示例代碼,也許有人會問,第二個雙精度類型的除法計算也應該拋出異常才對啊,在實際的運行過程中并非如此,其實該雙精度類型除法函數(shù)根本沒有被執(zhí)行過。以上程序的執(zhí)行規(guī)程為:調(diào)用函數(shù)Div(x,y)時發(fā)生異常,由函數(shù)Div中的語句"throw y"拋出異常,并不在往下執(zhí)行re
48、turn x/y,接著catch捕獲int類型的異常并處理異常,最后直接執(zhí)行"return 0"。因此函數(shù)Div(x1,y1)和catch(double)模塊根本沒有被執(zhí)行。如果,我們把y的值改為1,則結(jié)果就變成為: 如果在執(zhí)行try語句模塊時,沒有發(fā)生異常,則catch語句塊不起作用,流程轉(zhuǎn)到其后的語句繼續(xù)執(zhí)行。從上述兩個結(jié)果中可知第一次throw拋出的int類型所以找到處理該類型的catch,而第二次是拋出double類型所找到的是處理double類型的catch。下面對異常處理補充幾點:(1)try和catch塊中必須要用花括號括起來,即使花括號內(nèi)只有一個語
49、句也不能省略花括號;(2)try和catch必須成對出現(xiàn),一個try_catch結(jié)果中只能有一個try塊,但可以有多個catch塊,以便與不同的異常信息匹配;(3)如果在catch塊中沒有指定異常信息的類型,而用刪節(jié)號".",則表示它可以捕獲任何類型的異常信息;(4)如果throw不包括任何表達式,表示它把當前正在處理的異常信息再次拋出,傳給其上一層的catch來處理;(5)C+中一旦拋出一個異常,如果程序沒有任何的捕獲,那么系統(tǒng)將會自動調(diào)用一個系統(tǒng)函數(shù)terminate,由它調(diào)用abort終止程序;最后還是一樣,我將用一個示例來總結(jié)一下今天所講的內(nèi)容(開發(fā)工具:#incl
50、ude <iostream> template <class T>T Div(T x,T y) if(y=0) throw y;/拋出異常 return x/y; int main() int x=5,y=1; double x1=5.5,y1=0.0; try std:cout<<x<<"/"<<y<<"="<<Div(x,y)<<std:endl; std:cout<<x1<<"/"<<y1<&
51、lt;"="<<Div(x1,y1)<<std:endl; catch(.)/捕獲任意類型異常 try std:cout<<"任意類型異常!"<<std:endl; throw;/拋出當前處理異常信息給上一層 catch(int)/異常類型0 std:cout<<"除數(shù)為0,計算錯誤!"<<std:endl;/異常處理語 catch(double)/異常類型 std:cout<<"除數(shù)為0.0,計算錯誤!"<<std:e
52、ndl;/異常處理語 return 0; 異常的誤用 異常處理并不是用來限制出現(xiàn)錯誤,一些程序員可能會簡單的使用它來作為循環(huán)的選擇控制結(jié)構(gòu)。例如,一個簡單的應用程序讓用戶輸入數(shù)據(jù)直到一個特定的條件滿足: #include <iostream> using namespace std; class Exit; /used as exception object int main() int num;
53、160;cout<< "enter a number; 99 to exit" <<endl; try while (true) /infinitely cin>>num; if (num = 99) throw Exit(); /exit the loop cout<< &q
54、uot;you entered: " << num << "enter another number " <<endl; catch (Exit& ) cout<< "game over" <<endl; return 0;
55、0;在上面的例子中,程序員把一個無限循環(huán)放在了try block中,throw語句終止循環(huán)并且把控制權(quán)傳遞給后面的catch語句。這種編程樣式不應該被推薦。它的效率會非常低下因為異常處理存在。在上面小的演示程序中,或許僅僅是程序樣式的差異,但是在大規(guī)模的應用系統(tǒng)中,使用異常處理來作為控制選擇控制結(jié)構(gòu)的話,那么將會帶來顯著的效率損失。 標準異常 C+定義了一個標準異常層次,當在運行時發(fā)生反常情形時拋出。標準異常類從std:exception(在<stdexcept>頭文件中定義)派生。這一層次使得應用程序能夠在單一的catch語句中捕獲這些異常:
56、0;catch (std:exception& exc) / handle exception of type std:exception as well as /any exception derived from it 那些通過語言內(nèi)建操作符拋出的標準異常是: std:bad_alloc /by operator new std:
57、bad_cast /by operator dynamic_cast < > std:bad_typeid /by operator typeid std:bad_exception /thrown when an exception specification of 所有的標準異常都提供了成員函數(shù)what(),它返回一個用來描述異常細節(jié)的字符串。注意,標準庫還有另外一個被它的組件拋出的的異常集合。
58、160;異常處理層次 異常在一個自下向上的層次中捕獲:派生層次越深的異常越先被處理,例如: #include <stdexcept> #include <iostream> using namespace std; int main() try char * buff = new char100000000; /.use buff catch(bad_alloc& alloc_failure) / bad_alloc is /derived from exception cout<<
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 房地產(chǎn)市場報告 -2024年四季度青島寫字樓和零售市場報告
- 2025廣告公司采購合同
- 2025食品代理合同樣本
- 二零二五年度數(shù)字貨幣內(nèi)部股東股權(quán)轉(zhuǎn)讓合同模板3篇
- 二零二五年度農(nóng)業(yè)機械設備租賃與農(nóng)產(chǎn)品加工服務合同3篇
- 2025年度鄉(xiāng)村振興戰(zhàn)略下全新貧困戶幫扶合作協(xié)議3篇
- 二零二五年度車輛維修版服務合同3篇
- 二零二五年度全新私人合同:私人健身俱樂部及健身器材租賃服務協(xié)議2篇
- 二零二五年度企業(yè)個人業(yè)績目標對賭協(xié)議3篇
- 2025年度環(huán)??萍己匣锶斯蓹?quán)分配與綠色發(fā)展合同3篇
- 護士條例課件
- 結(jié)腸鏡檢查前腸道準備
- 創(chuàng)業(yè)基礎知識競賽題庫及答案
- (高清版)TDT 1063-2021 國土空間規(guī)劃城市體檢評估規(guī)程
- 國有企業(yè)股權(quán)轉(zhuǎn)讓規(guī)定
- 收費站一站一品方案
- 2024年保險考試-車險查勘定損員筆試歷年真題薈萃含答案
- 2024屆湖南省長沙市高三新高考適應性考試生物試題(含答案解析)
- 2024年四川省普通高中學業(yè)水平考試(思想政治樣題)
- 精液的常規(guī)檢測課件
- 《青紗帳-甘蔗林》 課件 2024年高教版(2023)中職語文基礎模塊下冊
評論
0/150
提交評論