程序異常處理_第1頁(yè)
程序異常處理_第2頁(yè)
程序異常處理_第3頁(yè)
程序異常處理_第4頁(yè)
程序異常處理_第5頁(yè)
已閱讀5頁(yè),還剩19頁(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)介

1、C+之異常處理一個(gè)好的程序應(yīng)該能對(duì)多種不同的特殊情況,做出不同的反應(yīng),對(duì)于突發(fā)情況也應(yīng)有對(duì)應(yīng)的處理方法。我們?cè)诰幊虝r(shí)應(yīng)考慮到各種突發(fā)情況,并在程序中給出解決方案,使程序的健壯性增強(qiáng)。假設(shè)有一個(gè)司機(jī)從A地開(kāi)車前往B地。若在某處有一岔路口,一般選擇左邊,路程會(huì)近一些。但當(dāng)司機(jī)選擇左邊,將車開(kāi)到途中時(shí)發(fā)現(xiàn)正在修路(突發(fā)情況),無(wú)法通過(guò)。這時(shí),司機(jī)就會(huì)掉頭回到剛才的岔路口處,重新選擇右邊的路,繼續(xù)前進(jìn)。 我們所編的程序也應(yīng)該像這樣,有一定的智能化的設(shè)計(jì)。這就要求在編寫程序時(shí),應(yīng)該試著確定程序可能出現(xiàn)的錯(cuò)運(yùn),然后加入處理錯(cuò)誤的代碼。例如:當(dāng)程序執(zhí)行文件I0操作時(shí),應(yīng)測(cè)試文件打開(kāi)以及讀寫操作是否成功,并且

2、在出現(xiàn)錯(cuò)誤時(shí)做出正確的反應(yīng)。隨著程序復(fù)雜性的增加,為處理錯(cuò)誤而必須包括在程序中代碼的復(fù)雜性也相應(yīng)地增加了。為使程序更易于測(cè)試和處理錯(cuò)誤,C+實(shí)現(xiàn)了異常處理機(jī)制。一、異常概念 1異常的概念程序的錯(cuò)誤,一種是編譯錯(cuò)誤,即語(yǔ)法錯(cuò)誤。如果使用了錯(cuò)誤的語(yǔ)法、函數(shù)、結(jié)構(gòu)和類,程序就無(wú)法被生成運(yùn)行代碼。另一種是在運(yùn)行時(shí)發(fā)生的錯(cuò)誤,它分為不可預(yù)料的邏輯錯(cuò)誤和可以預(yù)料的運(yùn)行異常。運(yùn)行異常,可以預(yù)料,但不能避免,它是由系統(tǒng)運(yùn)行環(huán)境造成的。如,內(nèi)存空間不足,而程序運(yùn)行中提出內(nèi)存分配申請(qǐng)時(shí),得不到滿足,就會(huì)發(fā)生異常:#include<fstream.h>/void f(char *str)ifstream

3、 source(str); 打開(kāi)str串中的文件if(sourcefail()打不開(kāi)cerr <<"Error opening the file:"<<str <<endl; exit(1); 退出程序 /當(dāng)程序?qū)ξ募虿婚_(kāi)時(shí),程序會(huì)打印提示信息,并由exit(1)函數(shù)退出。這樣就不至于會(huì)因?yàn)槲募虿婚_(kāi)而導(dǎo)致整個(gè)程序在運(yùn)行過(guò)程中停滯或錯(cuò)亂。2異常的基本思想 在小型程序中,一旦發(fā)生異常,一般是將程序立即中斷運(yùn)行,從而無(wú)條件釋放所有資源。對(duì)于大型程序來(lái)說(shuō),運(yùn)行中一旦發(fā)生異常,應(yīng)該允許恢復(fù)和繼續(xù)運(yùn)行?;謴?fù)的過(guò)程就是把產(chǎn)生異常所造成的惡劣影響去掉

4、,中間可能要涉及一系列的函數(shù)調(diào)用鏈的退棧,對(duì)象的析構(gòu),資源的釋放等。繼續(xù)運(yùn)行就是異常處理之后,在緊接著異常處理的代碼區(qū)域中繼續(xù)運(yùn)行。在C+中,異常是指從發(fā)生問(wèn)題的代碼區(qū)域傳遞到處理問(wèn)題的代碼區(qū)域的一個(gè)對(duì)象。見(jiàn)圖 :發(fā)生異常的地方在函數(shù)k()中,處理異常的地方在其上層函數(shù)f()中,處理異常后,函數(shù)k()和g()都退棧,然后程序在函數(shù)f()中繼續(xù)運(yùn)行。如果不用異常處理機(jī)制,在程序中單純地嵌入錯(cuò)誤處理語(yǔ)句,要實(shí)現(xiàn)這一目的是艱難的。 異常的基本思想是:(1)實(shí)際的資源分配(如內(nèi)存申請(qǐng)或文件打開(kāi))通常在程序的低層進(jìn)行,如圖中的k()。(2)當(dāng)操作失敗、無(wú)法分配內(nèi)存或無(wú)法打開(kāi)一個(gè)文件時(shí)在邏輯上如何進(jìn)行處理

5、通常是在程序的高層,如圖中的f(),中間還可能有與用戶的對(duì)話。 (3)異常為從分配資源的代碼轉(zhuǎn)向處理錯(cuò)誤狀態(tài)的代碼提供了一種表達(dá)方式。如果還存在中間層次的函數(shù),如圖中的g(),則為它們釋放所分配的內(nèi)存提供了機(jī)會(huì),但這并不包括用于傳遞錯(cuò)誤狀態(tài)信息的代碼。 從中可以看出,C什異常處理的目的,是在異常發(fā)生時(shí),盡可能地減小破壞,周密地善后,而不去影響其它部分程序的運(yùn)行。-這在大型程序中是非常必要的。例如對(duì)于以前所講的程序調(diào)用關(guān)系,如處理文件打開(kāi)失敗異常的方法,那么,異常只能在發(fā)生的函數(shù)k()中進(jìn)行處理,無(wú)法直接傳遞到函數(shù)f()中,而且調(diào)用鏈中的函數(shù)g()的善后處理也十分困難。二、異常的實(shí)現(xiàn)使用異常的步

6、驟是:(1)定義異常(try語(yǔ)句塊) 將那些可能產(chǎn)生錯(cuò)誤的語(yǔ)句框定在try語(yǔ)句中;(2)定義異常處理(catch語(yǔ)句塊)將異常處理的語(yǔ)句放在catch塊中,以便異常被傳遞過(guò)來(lái)時(shí)就處理它;(3)拋擲異常(throw語(yǔ)句)檢測(cè)是否產(chǎn)生異常,若產(chǎn)生異常,則拋擲異常。例如,下面的程序,設(shè)置了防備文件打不開(kāi)的異常:例題1#include <fstream.h>#include <iostream.h>#include <stdlib.h>void main(int argc,char *argv) ifstream source(argv1); /打開(kāi)文件 char

7、line128;try if(source.fail() /如果打開(kāi)失敗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();運(yùn)行結(jié)果:假定C盤中沒(méi)有abc.txt文件,有xyz.txt文件,內(nèi)容為: How are you? Fine!兩行語(yǔ)句

8、,則運(yùn)行結(jié)果為:在c:>提示符后輸入命令 ch10_1 abc.txt屏幕顯示結(jié)果為: error opening the file abc.txt若輸入命令 ch10_1 xyz.txt則屏幕顯示結(jié)果為: How are you? Fine!例題2:一個(gè)除零異常:#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; 運(yùn)行結(jié)果為:7.3/2.0=3.65except of deviding zer

10、o!That is ok.三、 異常處理機(jī)制在處理程序和語(yǔ)句之間的相互作用使異常在大型應(yīng)用程序中變得復(fù)雜。通常人們希望拋擲被及時(shí)捕獲,以避免程序突然終止。此外,跟蹤拋擲很重要,因?yàn)椴东@確定該程序的后繼進(jìn)展。例如,拋擲和捕獲可以用來(lái)重新開(kāi)始程序內(nèi)的一個(gè)過(guò)程,或者從應(yīng)用程序的一部分跳到另一部分,或者回到菜單。例如,項(xiàng)目的代碼說(shuō)明了異常處理機(jī)制。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ù)為省略號(hào),定義一個(gè)"默認(rèn)"的異常處理程序。通常這個(gè)處理程序應(yīng)在所有異常處理塊的最后,因?yàn)樗c任何throw都匹配,目的是為避免定義的異常處理程序沒(méi)能捕獲拋擲的異常而使程序運(yùn)行終止。函數(shù)h()中的catch(Size)塊,包含有一個(gè)拋擲異常語(yǔ)句throw 10,當(dāng)實(shí)際執(zhí)行這條語(yǔ)句時(shí),將沿著調(diào)用鏈向上傳遞被函數(shù)f()中的c

12、atch(.)所捕獲。如果沒(méi)有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塊后的異常處理程序,可是沒(méi)有被捕獲,因而它又沿函數(shù)調(diào)用鏈向上,在函數(shù)f()中,catch(Range)塊終于捕獲了該拋擲。函數(shù)h1()中的catch(Size)塊,包含一個(gè)拋擲throw,沒(méi)有帶參數(shù)類型,它表示將捕獲到的異常對(duì)象重新拋擲出

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è)異常組成族系。構(gòu)成異常族系的一些實(shí)力又?jǐn)?shù)學(xué)錯(cuò)誤異常族系和文件處理錯(cuò)誤異常族系。在C+代碼中把異常組在一起有兩種方式:異常枚舉族系和異常派生層次結(jié)構(gòu)。例如,下面的代碼是一個(gè)異常枚舉族系的例子:

14、enmu FileErrorsnonExist,wrongformat,diakSeekError,.;int f() try /. throw wrongFormat;catch(FileErrors fe) switch(fe) case nonExist: /.case wrongFormat: /. case diskSeekError: /./.在try塊中有一個(gè)throw,它拋擲一個(gè)FileError枚舉中的常量。這個(gè)拋擲可被catch(FileErrors)塊捕獲到,接著后者執(zhí)行一個(gè)switch,對(duì)照情況列表,匹配捕獲到的枚舉常量值。上面的異常族系也可按異常派生層次結(jié)構(gòu)來(lái)實(shí)現(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) /./.上面的各異常處理程序塊定義了針對(duì)類NonExist和DiskSeekError的派生異常類對(duì)象,針對(duì)FileErrors的異常處理,既捕獲FileEr

16、rors類對(duì)象,也捕獲WrongFormat對(duì)象。異常捕獲的規(guī)則除了前面所說(shuō)的,必須嚴(yán)格匹配數(shù)據(jù)類型外,對(duì)于類的派生,下列情況可以捕獲異常:(1) 異常處理的數(shù)據(jù)類型是公有基類,拋擲異常的數(shù)據(jù)類型是派生類;(2) 異常處理的數(shù)據(jù)類型是指向公有基類的指針,拋擲異常的數(shù)據(jù)類型是指向派生類的指針。 對(duì)于派生層次結(jié)構(gòu)的異常處理,catch塊組中的順序是重要的。因?yàn)?quot;catch(基類)"總能夠捕獲"throw派生類對(duì)象"。所以"catch(基類)"塊總是放在"catch(派生類)"塊的后面,以避免"catch(派生

17、類)"永遠(yuǎn)不能捕獲異常。五、 異常的再提出(rethrowing) 有時(shí)候會(huì)發(fā)生一個(gè)異常處理句柄接收了一個(gè)異常卻發(fā)現(xiàn)不能處理這個(gè)異常的情況。這時(shí),這個(gè)異??梢员辉偬岢鲆员阌谄渌浔軌蚋玫奶幚?。異常的再提出可以通過(guò)一個(gè)空的throw表達(dá)語(yǔ)句來(lái)實(shí)現(xiàn)。但是,這種表達(dá)語(yǔ)句只能出現(xiàn)于一個(gè)異常處理句柄中。例如, void f() try showWindow(); /提出CoDialogException類異常 catch (CoWindowException& WinExc) WinExc.repaint(); throw; /異常再提出 void g() try f(); cat

18、ch (CoDialogException& DialogExc) /*異常處理語(yǔ)句*/ catch (CoWindowException& WindowExc) /*異常處理語(yǔ)句*/ 上述例子中,盡管CoDialogException類異常是由函數(shù)f()中的CoWindowException類處理句柄再提出的,但是它仍然由函數(shù)g()中的CoDialogException類異常處理句柄來(lái)處理。 此外,任何異常都可以通過(guò)一種特殊的接收方式catch(.)來(lái)接收和處理。例如下面例子中的f()函數(shù)可以接收任何異常并再提出。 void f() try showWindow(); cat

19、ch(.) /接收任何異常 /某些處理語(yǔ)句 throw; 值得注意的是,異常的再提出并不對(duì)異常對(duì)象進(jìn)行進(jìn)一步的拷貝。 #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)。第二個(gè)在func()中的try block拋出一個(gè)FileException類型的異常(2)。這個(gè)異常被fun

26、c()內(nèi)的catch block所捕獲(3)。那個(gè)catch block試圖通過(guò)打開(kāi)一個(gè)新文件進(jìn)行補(bǔ)救,但是失敗了(5),并且FileException異常被重新拋出(6)。最終,那個(gè)重新拋出的異常被main()中的catch()所捕獲(7)。  六. 在異常對(duì)象中攜帶更多的信息 異常對(duì)象如同其它類對(duì)象一樣可以攜帶信息。所以一個(gè)異常對(duì)象可以被用來(lái)將一些有用信息從提出點(diǎn)攜帶到接收處理點(diǎn)。這些信息可以是當(dāng)程序在運(yùn)行過(guò)程中出現(xiàn)非正常情況時(shí)程序使用者想要知道的。例如一個(gè)程序使用者可能想知道一個(gè)矢量的下標(biāo),當(dāng)這個(gè)矢量下標(biāo)超限時(shí)。 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; 實(shí)際上,catch后面括弧中的表達(dá)語(yǔ)句實(shí)際上類似于函數(shù)的參數(shù)定義。 七、 句柄的次序 異常處理句柄有先后次序之分。因?yàn)橐粋€(gè)派生(derived)異常類對(duì)象可以被幾個(gè)句柄接收,所以在排列異常處理句柄順序時(shí)應(yīng)該特別小心。另外,一個(gè)類型嚴(yán)格匹配的處理句柄并不

29、比一個(gè)需要類型轉(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; /其它表達(dá)語(yǔ)句 catch (void * pVoid) /* . */ catch (PCF pFunction) /* . */ catch (const CoWindow& win) /* . */ catch (const CoButton

30、& button) /* . */ catch (.) /* . */ return; 在上面例子中,(void *)處理句柄不可能允許它后面的PCF處理句柄被調(diào)用。類似的,因?yàn)镃oWindow類處理句柄將會(huì)接收任何CoWindow類及它的衍生類對(duì)象,所以CoButton類的處理句柄也不會(huì)被調(diào)用。依賴于你所使用的編譯器,有的編譯器可能在編譯時(shí)警告你一個(gè)從類B派生來(lái)的類D句柄放在類B句柄后面。但是,如果一個(gè)接收任何異常的句柄catch(.)不是最后一個(gè)句柄,編譯器會(huì)給出編譯錯(cuò)誤。派生類組織異常;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) 八、 異常提出過(guò)程中的對(duì)象構(gòu)造和析構(gòu) 當(dāng)一個(gè)程序由于異常而中斷時(shí),所有的從try開(kāi)始構(gòu)造的自動(dòng)變量類的對(duì)象都會(huì)被清除、釋放。這種調(diào)用自動(dòng)變量類的析構(gòu)函數(shù)的過(guò)程稱為堆棧清除(stack unwinding)。下面給出了一個(gè)實(shí)例。 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; 這個(gè)例子給出了下面輸出結(jié)果。 當(dāng) catch( const CoError e) 時(shí)CoClass(int): 169 CoClass(int): 0 CoError(int): 13 CoError(const CoError&): 13 CoClass(): 0 CoClass(): 169 Caught : 13 CoError(): 13 CoError(): 13 當(dāng) catch( const CoEr

35、ror & e) 時(shí)CoClass(int): 169 CoClass(int): 0 CoError(int): 13 CoClass(): 0 CoClass(): 169 Caught : 13 CoError(): 13 當(dāng)一個(gè)異常在一個(gè)類對(duì)象的構(gòu)造過(guò)程中被提出時(shí),如果這個(gè)類對(duì)象中包含了其它成員類對(duì)象,那么那些在異常提出前完成了構(gòu)造的成員類對(duì)象的析構(gòu)函數(shù)會(huì)被調(diào)用來(lái)清除已構(gòu)造了的成員對(duì)象。而那些沒(méi)有完成構(gòu)造的成員類對(duì)象的析構(gòu)函數(shù)不會(huì)被調(diào)用。例如,如果在構(gòu)造一個(gè)類對(duì)象的數(shù)組過(guò)程中一個(gè)異常被提出,那么只有那些完成了構(gòu)造的對(duì)象的析構(gòu)函數(shù)才被調(diào)用來(lái)進(jìn)行堆棧清除。 接收一個(gè)析構(gòu)函數(shù)提出的異

36、常也是可能的。將調(diào)用析構(gòu)函數(shù)的函數(shù)放在try后面的程序塊中,并且提供適當(dāng)?shù)念愋途浔涂梢粤恕?九、 函數(shù)的異常規(guī)范 一個(gè)函數(shù)的參數(shù)串稱之為這個(gè)函數(shù)的簽名(signature),因?yàn)樗?jīng)常被用來(lái)區(qū)別一個(gè)函數(shù)實(shí)體。一個(gè)函數(shù)由四個(gè)部分組成。(1)返回類型。(2)函數(shù)名。(3)函數(shù)簽名。(4)函數(shù)體。前三個(gè)部分常稱作為函數(shù)原型(function prototype).函數(shù)原型提供給了編譯器關(guān)于這個(gè)函數(shù)的類型信息。編譯器通過(guò)這些信息進(jìn)行類型診斷。通常一個(gè)函數(shù)的使用者只需要知道這個(gè)函數(shù)原型就可以了。但是如果使用者想寫這個(gè)函數(shù)所提出的所有異常句柄,那么這個(gè)使用者就需要知道這些異常類型。 要解決這個(gè)問(wèn)題,一個(gè)

37、函數(shù)原型或者定義(definition)可以包括異常規(guī)范(exception specifications)。異常規(guī)范出現(xiàn)在一個(gè)函數(shù)定義后面。它列出了這個(gè)函數(shù)可以直接或間接提出的異常。例如下面給出了一些函數(shù)的原型 void f() throw(v1, v2, v3); void g(); void h() throw(); void e() throw(WClass *); f()的定義表明了這個(gè)函數(shù)可以提出類型v1,v2和v3,以及它們的派生類型。如果函數(shù)f()提出除此以外的其它異常,程序在運(yùn)行中會(huì)產(chǎn)生一個(gè)運(yùn)行錯(cuò)誤。函數(shù)g()的定義沒(méi)有包含異常規(guī)范。這意味著它可以提出任何異常。而函數(shù)h()則

38、不能提出任何異常。函數(shù)e()可以提出WClass類的指針型異常,或者由WClass派生來(lái)的類指針異常。 一個(gè)函數(shù)后面的異常規(guī)范并不屬于這個(gè)函數(shù)指針中的一部分。然而當(dāng)一個(gè)指向函數(shù)的指針賦值給指向另一個(gè)函數(shù)的指針時(shí),只有在被賦值的指針函數(shù)包含了賦值指針函數(shù)的異常時(shí)才允許。例如 void (*pf1)(); /沒(méi)有異常規(guī)范 void (*pf2)() throw(int); /只能提出整型異常 void f() pf1 = pf2; /可以,pf1要求比較寬松 pf2 = pf1; /錯(cuò)誤,pf2要求更嚴(yán)格 下面函數(shù) void f() throw(v1,v2,v3) SomeAction(); 相當(dāng)

39、于 void f() try SomeAction(); catch(v1 v) throw; /在提出 catch(v2 v) throw; /在提出 catch(v3 v) throw; /在提出 catch(.) unexpected(); /定義在頭文件<exception>中 當(dāng)一個(gè)函數(shù)提出的異常沒(méi)有包括在這個(gè)函數(shù)的異常規(guī)范中時(shí),程序會(huì)自動(dòng)調(diào)用函數(shù)unexpected()來(lái)處理這個(gè)異常。函數(shù)unexpected()的缺省行為是調(diào)用使用者通過(guò)set_unexpected()函數(shù)注冊(cè)的函數(shù)。假如沒(méi)有任何函數(shù)通過(guò)set_unexcepted()來(lái)注冊(cè),函數(shù)unexpected(

40、)則調(diào)用函數(shù)terminate()。這三個(gè)函數(shù)的原型如下。 void unexpected(); typedef void (*unexpected_handler)(); unexpected_handler set_unexpected(unexpected_handler) throw(); void terminate(); 函數(shù)set_unexpected()的返回值是前一次通過(guò)set_unexpected()注冊(cè)的函數(shù)指針。 函數(shù)terminate()可以通過(guò)unexpected()來(lái)調(diào)用,或者當(dāng)找不到一個(gè)異常句柄時(shí)程序自動(dòng)調(diào)用。terminate()函數(shù)的缺省行為是調(diào)用函數(shù)abo

41、rt()。這個(gè)缺省函數(shù)即刻中止程序運(yùn)行。你可以改變當(dāng)一個(gè)異常沒(méi)有出現(xiàn)于函數(shù)的異常規(guī)范中時(shí)的程序中止方式。如果你不想你的程序通過(guò)調(diào)用abort()來(lái)中止,你可以定義另外一個(gè)函數(shù)來(lái)替代它。這樣的函數(shù)通過(guò)set_terminate()函數(shù)來(lái)注冊(cè)并由terminate()調(diào)用。函數(shù)set_terminate()的定義如下 typedef void (*terminate_handler)(); terminate_handler set_terminate(terminate_handler) throw(); 這個(gè)函數(shù)的返回值是前一次通過(guò)函數(shù)set_terminate()來(lái)注冊(cè)的函數(shù)指針。 頭文件&

42、lt;exception>定義了處理異常的函數(shù),類及其數(shù)據(jù)成員和成員函數(shù)。 十、 具有異常規(guī)范的虛擬函數(shù) 一個(gè)虛擬函數(shù)也可以定義異常規(guī)范。但是,一個(gè)子類中的虛擬函數(shù)提出的異常不能比父類中的虛擬函數(shù)提出的異常多。也就是說(shuō),一個(gè)子類中的虛擬函數(shù)規(guī)范不能比父類中的虛擬函數(shù)規(guī)范更寬松。而一個(gè)子類中的虛擬函數(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); /錯(cuò)誤,異常規(guī)范較寬松 virtual void getFocus() throw(int); /可以,異常規(guī)范更嚴(yán)歷 ; 編譯器針對(duì)CoDialog:show()會(huì)給出編譯錯(cuò)誤,因?yàn)樵谶\(yùn)行時(shí)這個(gè)函數(shù)既可以提出int類型異常也可以提出char類型異常。而在父類定義中,這個(gè)虛擬函數(shù)只能提出int類型異常。另一方面,CoDialog:getFocus()是允許的,因?yàn)樗囊?guī)范比父類中的虛擬函數(shù)的異常規(guī)范要求更嚴(yán)歷。 例題:下面我們用示例演示一下異常處理: 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、         /被檢查的語(yǔ)句      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,計(jì)算錯(cuò)誤!"<<std:endl;/異常處理語(yǔ)句         catch(double)/異常類型      &

47、#160;       std:cout<<"除數(shù)為0.0,計(jì)算錯(cuò)誤!"<<std:endl;/異常處理語(yǔ)句29     return 0; 結(jié)果: 看了上述的示例代碼,也許有人會(huì)問(wèn),第二個(gè)雙精度類型的除法計(jì)算也應(yīng)該拋出異常才對(duì)啊,在實(shí)際的運(yùn)行過(guò)程中并非如此,其實(shí)該雙精度類型除法函數(shù)根本沒(méi)有被執(zhí)行過(guò)。以上程序的執(zhí)行規(guī)程為:調(diào)用函數(shù)Div(x,y)時(shí)發(fā)生異常,由函數(shù)Div中的語(yǔ)句"throw y"拋出異常,并不在往下執(zhí)行re

48、turn x/y,接著catch捕獲int類型的異常并處理異常,最后直接執(zhí)行"return 0"。因此函數(shù)Div(x1,y1)和catch(double)模塊根本沒(méi)有被執(zhí)行。如果,我們把y的值改為1,則結(jié)果就變成為: 如果在執(zhí)行try語(yǔ)句模塊時(shí),沒(méi)有發(fā)生異常,則catch語(yǔ)句塊不起作用,流程轉(zhuǎn)到其后的語(yǔ)句繼續(xù)執(zhí)行。從上述兩個(gè)結(jié)果中可知第一次throw拋出的int類型所以找到處理該類型的catch,而第二次是拋出double類型所找到的是處理double類型的catch。下面對(duì)異常處理補(bǔ)充幾點(diǎn):(1)try和catch塊中必須要用花括號(hào)括起來(lái),即使花括號(hào)內(nèi)只有一個(gè)語(yǔ)

49、句也不能省略花括號(hào);(2)try和catch必須成對(duì)出現(xiàn),一個(gè)try_catch結(jié)果中只能有一個(gè)try塊,但可以有多個(gè)catch塊,以便與不同的異常信息匹配;(3)如果在catch塊中沒(méi)有指定異常信息的類型,而用刪節(jié)號(hào)".",則表示它可以捕獲任何類型的異常信息;(4)如果throw不包括任何表達(dá)式,表示它把當(dāng)前正在處理的異常信息再次拋出,傳給其上一層的catch來(lái)處理;(5)C+中一旦拋出一個(gè)異常,如果程序沒(méi)有任何的捕獲,那么系統(tǒng)將會(huì)自動(dòng)調(diào)用一個(gè)系統(tǒng)函數(shù)terminate,由它調(diào)用abort終止程序;最后還是一樣,我將用一個(gè)示例來(lái)總結(jié)一下今天所講的內(nèi)容(開(kā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;/拋出當(dāng)前處理異常信息給上一層 catch(int)/異常類型0 std:cout<<"除數(shù)為0,計(jì)算錯(cuò)誤!"<<std:endl;/異常處理語(yǔ) catch(double)/異常類型 std:cout<<"除數(shù)為0.0,計(jì)算錯(cuò)誤!"<<std:e

52、ndl;/異常處理語(yǔ) return 0;  異常的誤用 異常處理并不是用來(lái)限制出現(xiàn)錯(cuò)誤,一些程序員可能會(huì)簡(jiǎn)單的使用它來(lái)作為循環(huán)的選擇控制結(jié)構(gòu)。例如,一個(gè)簡(jiǎn)單的應(yīng)用程序讓用戶輸入數(shù)據(jù)直到一個(gè)特定的條件滿足: #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;在上面的例子中,程序員把一個(gè)無(wú)限循環(huán)放在了try block中,throw語(yǔ)句終止循環(huán)并且把控制權(quán)傳遞給后面的catch語(yǔ)句。這種編程樣式不應(yīng)該被推薦。它的效率會(huì)非常低下因?yàn)楫惓L幚泶嬖凇T谏厦嫘〉难菔境绦蛑?,或許僅僅是程序樣式的差異,但是在大規(guī)模的應(yīng)用系統(tǒng)中,使用異常處理來(lái)作為控制選擇控制結(jié)構(gòu)的話,那么將會(huì)帶來(lái)顯著的效率損失。 標(biāo)準(zhǔn)異常 C+定義了一個(gè)標(biāo)準(zhǔn)異常層次,當(dāng)在運(yùn)行時(shí)發(fā)生反常情形時(shí)拋出。標(biāo)準(zhǔn)異常類從std:exception(在<stdexcept>頭文件中定義)派生。這一層次使得應(yīng)用程序能夠在單一的catch語(yǔ)句中捕獲這些異常:

56、0;catch (std:exception& exc)  / handle exception of type std:exception as well as  /any exception derived from it  那些通過(guò)語(yǔ)言內(nèi)建操作符拋出的標(biāo)準(zhǔn)異常是: 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  所有的標(biāo)準(zhǔn)異常都提供了成員函數(shù)what(),它返回一個(gè)用來(lái)描述異常細(xì)節(jié)的字符串。注意,標(biāo)準(zhǔn)庫(kù)還有另外一個(gè)被它的組件拋出的的異常集合。&#

58、160;異常處理層次 異常在一個(gè)自下向上的層次中捕獲:派生層次越深的異常越先被處理,例如: #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. 本站所有資源如無(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ù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 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)論