C++程序設(shè)計(jì)第十五章異常_第1頁(yè)
C++程序設(shè)計(jì)第十五章異常_第2頁(yè)
C++程序設(shè)計(jì)第十五章異常_第3頁(yè)
C++程序設(shè)計(jì)第十五章異常_第4頁(yè)
C++程序設(shè)計(jì)第十五章異常_第5頁(yè)
已閱讀5頁(yè),還剩27頁(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+程序設(shè)計(jì)第15章異常程序中經(jīng)常要檢查處理各種錯(cuò)誤情形,如果用傳統(tǒng)的流程控制語(yǔ)句來(lái)處理,很容易使程序邏輯混亂。異常(exception)就是一種專門用于檢測(cè)錯(cuò)誤并處理的一種機(jī)制,使程序保持邏輯清晰,并改進(jìn)程序的可靠性。C+語(yǔ)言提供了基本的異常處理機(jī)制。本章主要介紹異常的概念、語(yǔ)句、異常類型架構(gòu)及應(yīng)用??煽康木幊虘?yīng)盡可能地、及時(shí)地檢測(cè)到各種異常情形,盡可能在本地處理。盡管有時(shí)自己不能處理,也應(yīng)該向調(diào)用方提供詳細(xì)的出錯(cuò)信息,使調(diào)用方能得到充分信息,從而采取合適方式來(lái)處理異常。15.1異常的概念異常是什么概念?異常就是在程序運(yùn)行中發(fā)生的難以預(yù)料的、不正常的事件而導(dǎo)致偏離正常流程的現(xiàn)象。例如:訪問(wèn)數(shù)

2、組元素的下標(biāo)越界,在越界時(shí)又寫入了數(shù)據(jù);用new動(dòng)態(tài)申請(qǐng)內(nèi)存而返回空指針(可能是因內(nèi)存不足);算術(shù)運(yùn)算上溢出或下溢出;整數(shù)除法中除數(shù)為0;調(diào)用函數(shù)時(shí)提供了無(wú)效實(shí)參,如指針實(shí)參為空指針(如用空指針來(lái)調(diào)用strlen函數(shù));通過(guò)掛空指針或掛空引用來(lái)訪問(wèn)對(duì)象;輸入整數(shù)或浮點(diǎn)數(shù)失敗;I/O錯(cuò)誤,等等。上面列出的情形之一如果發(fā)生,就可能導(dǎo)致運(yùn)行錯(cuò)誤而終止程序。發(fā)生異常將導(dǎo)致正常流程不能進(jìn)行,就需要對(duì)異常進(jìn)行處理。那么異常處理是什么概念?異常處理(exceptionhandling)就是在運(yùn)行時(shí)刻對(duì)異常進(jìn)行檢測(cè)、捕獲、提示、傳遞等過(guò)程。如果采用傳統(tǒng)的if-else語(yǔ)句來(lái)檢測(cè)處理所有可能發(fā)生的異常,很容易導(dǎo)

3、致程序流程混亂,分不清正常流程與異常處理,而且在處理一個(gè)異常時(shí)往往又引入了新的異常。假設(shè)要設(shè)計(jì)一個(gè)函數(shù),從一個(gè)文本文件中讀取數(shù)據(jù)得到一個(gè)float矩陣。該文件應(yīng)存放一個(gè)m*n的float矩陣,頭兩個(gè)整數(shù)說(shuō)明其行數(shù)m和列數(shù)n。你要把它讀入并創(chuàng)建一個(gè)矩陣對(duì)象,以備下一步計(jì)算。如果你認(rèn)為文本文件不會(huì)有錯(cuò),完全按正常編程,不超過(guò)10條語(yǔ)句就能完成。如果這個(gè)文本文件是別人提供的,而且你的函數(shù)將提供給其它人使用,那么你在每一步都要考慮可能出現(xiàn)的錯(cuò)誤,此時(shí)就可能需要30條語(yǔ)句來(lái)處理。例如,可能的出錯(cuò)情形如下:打開文件出錯(cuò),文件名可能有誤;讀取行數(shù)m或者列數(shù)n可能出錯(cuò);讀取每個(gè)元素時(shí)都可能出錯(cuò);矩陣數(shù)據(jù)可能不

4、完整,也會(huì)出錯(cuò)。如果你用傳統(tǒng)方式來(lái)判斷處理以上這些問(wèn)題,就會(huì)發(fā)現(xiàn)正常的流程被淹沒在多種異常判斷處理之中。此時(shí)就需要有一種統(tǒng)一的機(jī)制能將正常流程與異常處理分開描述,而保持程序邏輯清晰可讀,同時(shí)各種異常情形能被集中處理。C+提供了引發(fā)異常語(yǔ)句throw和捕獲處理異常語(yǔ)句try-catch。它們構(gòu)成了一種特殊的流程控制。用throw引發(fā)的每個(gè)異常都可以描述為一個(gè)對(duì)象或一個(gè)值。在程序中,每一種異常都可以描述為一種類型,可能是自定義的類,也可能是簡(jiǎn)單的整數(shù)或字符串。在比較完善的編程中,經(jīng)常用不同的類來(lái)描述不同的異常,建立一個(gè)異常類型的繼承結(jié)構(gòu),以方便對(duì)異常類型的管理和重用。一個(gè)函數(shù)中當(dāng)檢測(cè)到某種異常發(fā)生

5、,但自己往往不知道應(yīng)該如何處理,此時(shí)就應(yīng)該通知調(diào)用方知道發(fā)生了什么異常。處理異常的一般方式是:在一個(gè)函數(shù)中發(fā)現(xiàn)一個(gè)錯(cuò)誤但不能處理,就用throw語(yǔ)句引發(fā)一個(gè)異常,希望它的(直接或間接)調(diào)用方能夠捕獲并處理這個(gè)異常。函數(shù)的調(diào)用方如果能解決該異常,就可使用try-catch語(yǔ)句來(lái)捕獲并處理這種異常。如果調(diào)用方不能捕獲處理該異常,異常就被傳遞到它自己的調(diào)用方,最后到達(dá)main函數(shù)。異常的發(fā)生、傳遞與處理的過(guò)程與函數(shù)調(diào)用堆棧相關(guān)。如圖15.1所示。main函數(shù)中調(diào)用f函數(shù),f函數(shù)再調(diào)用g函數(shù)。如果g函數(shù)執(zhí)行return就正常返回到f。如果f執(zhí)行到return就正常返回到main。這是正常流程。如果g函

6、數(shù)在運(yùn)行時(shí)因檢測(cè)到某種錯(cuò)誤而用throw語(yǔ)句引發(fā)一個(gè)異常,而自己也沒有捕獲處理,此時(shí)該異常就被傳遞到f的調(diào)用方g函數(shù),而且g函數(shù)執(zhí)行終止(注意,不是返回)。對(duì)于f來(lái)說(shuō)就是g函數(shù)調(diào)用發(fā)生異常。此時(shí)如果f函數(shù)沒有捕獲該異常,那么異常又被傳遞到它的調(diào)用方main函數(shù),此時(shí)f函數(shù)執(zhí)行終止。同理,此時(shí)如果main也沒有捕獲該異常,那么程序就必須終止。此時(shí)系統(tǒng)可能會(huì)跳出一個(gè)對(duì)話框告知你發(fā)生了運(yùn)行錯(cuò)誤。在發(fā)生異常、傳遞異常的過(guò)程中,如果有一個(gè)函數(shù)用try-catch捕獲了該異常,就不會(huì)導(dǎo)致程序終止。在運(yùn)行時(shí)刻,一個(gè)異常只能被捕獲一次。假設(shè)f函數(shù)捕獲了這個(gè)異常,那么對(duì)于它的調(diào)用方main函數(shù)來(lái)說(shuō),就等于沒有發(fā)

7、生異常。異常編程的目的是改善程序的可靠性。在大型復(fù)雜程序中,完全不發(fā)生異常幾乎不可能,用傳統(tǒng)的if-else語(yǔ)句來(lái)檢查所有可能的異常情形,也有很大困難。編程正確性總是依賴某些假設(shè)成立為前提,異常編程就是要分析識(shí)別這些假設(shè)不成立的情形,采用面向?qū)ο缶幊碳夹g(shù)建立各種異常類型并形成繼承性架構(gòu),以處理程序中可能發(fā)生的各類異常。15.異2常類型的架構(gòu)C+的異常類型可以是任何類型,既可以是基本類型,如int整數(shù)、char*字符串,也可以是自定義類型。在比較規(guī)范的編程中,往往不能將基本類型作為異常類型。這是因?yàn)榛绢愋退鼙硎镜漠惓7N類有限。例如在一個(gè)程序中int類型只能表示一種異常情形,如果在不同函數(shù)中多

8、處引發(fā)不同語(yǔ)義的int異常,就很難區(qū)別不同int值的含義??赡鼙硎驹L問(wèn)數(shù)組的下標(biāo)越界,也可能表示打開文件不成功。在比較規(guī)范的編程中往往根據(jù)各種錯(cuò)誤情形,利用類的繼承性建立一個(gè)異常類型的架構(gòu),作用如下:對(duì)所處理的各種錯(cuò)誤情形進(jìn)行準(zhǔn)確描述、抽象和歸類。方便擴(kuò)展新的異常類型。在編程中方便選取引發(fā)正確的異常類型,也方便按類型來(lái)捕獲處理異常。圖15.2是定義在exception和vstdexcept中的一個(gè)異常類型架構(gòu)。在頭文件exception中定義了基類exception和一組函數(shù),在vstdexcept中定義了一組派生類,表示各類具體的異常。標(biāo)準(zhǔn)模板庫(kù)STL中的部分函數(shù)就利用了這個(gè)架構(gòu)。下面簡(jiǎn)單介

9、紹各種異常類型。類exception是所有異常類的基類,其公共成員如下:classexceptionpublic:exception()throw();/缺省構(gòu)造函數(shù)exception(constexception&rhs)throw();/拷貝構(gòu)造函數(shù)exception&operator=(constexception&rhs)throw();/賦值操作函數(shù)virtualexception()throw();/虛析構(gòu)函數(shù)virtualconstchar*what()constthrow();/虛函數(shù);注意到每個(gè)函數(shù)原型末尾都有“throw()”,稱為函數(shù)的異常規(guī)范(exception-spe

10、cification),括號(hào)中為空說(shuō)明該函數(shù)中不會(huì)引發(fā)任何異常出來(lái)。如果一個(gè)函數(shù)在執(zhí)行時(shí)可能引發(fā)某種異常類型,就應(yīng)該在“thow(異常類型表)”中說(shuō)明,以告知調(diào)用方。每個(gè)異常對(duì)象都至少包含一個(gè)字符串,來(lái)說(shuō)明異常發(fā)生的原因或出錯(cuò)性質(zhì),稱為出錯(cuò)信息。因此大多派生異常類都提供含字符串形參的構(gòu)造函數(shù)。例如:classinvalid_argument:publiclogic_errorpublic:invalid_argument(conststring&what_arg);/構(gòu)造函數(shù);一般地,派生類繼承基類的虛函數(shù)what(),返回出錯(cuò)信息。如果需要的話,派生類可以改寫這個(gè)虛函數(shù),以提供更多信息。類l

11、ogic_error表示邏輯錯(cuò)誤的異常類型,此類錯(cuò)誤是在特定代碼執(zhí)行之前就違背了某些前置條件,例如,數(shù)據(jù)越界out_of_range,函數(shù)調(diào)用實(shí)參無(wú)效invalid_argument等,也包括特定領(lǐng)域相關(guān)的錯(cuò)誤domain_error。讀者可自行擴(kuò)展新類型。例如,訪問(wèn)數(shù)據(jù)的下標(biāo)越界可作為out_of_range的派生類。一些邏輯錯(cuò)誤意味著編程有誤,一般通過(guò)改進(jìn)編程能避免。類runtime_error表示運(yùn)行期錯(cuò)誤,在程序執(zhí)行期間才能檢測(cè)的錯(cuò)誤。例如算術(shù)運(yùn)算可能導(dǎo)致上溢出overflow_error、下溢出underflow_error、數(shù)值越界range_error等。讀者可自行擴(kuò)展新的類型,

12、如空指針錯(cuò)誤可作為runtime_error的派生類。一些運(yùn)行期錯(cuò)誤有一定偶然性,與執(zhí)行環(huán)境有關(guān),如內(nèi)存不足、打開文件失敗等,此類錯(cuò)誤并不能通過(guò)改進(jìn)自身編程來(lái)消除。一個(gè)異常類所包含的信息越多,對(duì)于此類錯(cuò)誤的檢測(cè)和處理就越有利。例如,要說(shuō)明下標(biāo)越界錯(cuò)誤,就應(yīng)該說(shuō)明該下標(biāo)的當(dāng)前值是多少,可能的話,還應(yīng)說(shuō)明合理的下標(biāo)范圍。這需要添加新的數(shù)據(jù)成員以及相應(yīng)的成員函數(shù)。例如:classIndex_out_of_range:publicout_of_rangeconstintindex;public:Index_out_of_range(intindex1,conststring&what_arg):ind

13、ex(index1),out_of_range(what_arg)intgetIndex()constreturnindex;再如,要說(shuō)明讀取文件到特定位置時(shí)發(fā)生數(shù)據(jù)錯(cuò)誤,就應(yīng)該說(shuō)明文件名、出錯(cuò)位置、所讀到的數(shù)據(jù)等信息。后面將詳細(xì)介紹這些派生類的設(shè)計(jì)。大多數(shù)異常派生類都很簡(jiǎn)短,關(guān)鍵是對(duì)異常的識(shí)別和命名。C+異常分為兩類:有命名的和未命名的。有命名的異常是有類型的,基本類型(如int)或字符串(char*)或自定義類型。未命名的異常是在運(yùn)行時(shí)刻某種底層錯(cuò)誤引起的,例如,整數(shù)相除時(shí)除數(shù)為0,通過(guò)掛空指針或掛空引用來(lái)訪問(wèn)對(duì)象,破壞當(dāng)前函數(shù)的堆棧使函數(shù)返回到錯(cuò)誤地址等。未命名異常雖然也能被捕獲,但不能

14、提供確切的出錯(cuò)信息。建立異常類型架構(gòu)本質(zhì)上就是對(duì)各種異常情形的識(shí)別與命名,對(duì)于異常處理具有重要作用。15.3異常處理語(yǔ)句C+語(yǔ)言的異常處理語(yǔ)句包括引發(fā)異常語(yǔ)句throw和捕獲處理語(yǔ)句try-catch。語(yǔ)句引發(fā)異常語(yǔ)句的語(yǔ)法格式為:throw表達(dá)式;其中,關(guān)鍵字throw表示要引發(fā)一個(gè)異常到當(dāng)前作用域之外。表達(dá)式值的類型作為異常事件的類型,并將表達(dá)式的值傳給捕獲處理該類型異常的程序。表達(dá)式的值可能是一個(gè)基本類型的值,也可能是一個(gè)對(duì)象。如果要引發(fā)一個(gè)對(duì)象,對(duì)象類應(yīng)該事先設(shè)計(jì)好。一個(gè)類表示了一種異常事件,應(yīng)描述該類異常發(fā)生的原因、語(yǔ)境以及可能的處理方法等。如果在一個(gè)函數(shù)編程中發(fā)現(xiàn)了自己不能處理的錯(cuò)

15、誤情形,就可使用throw語(yǔ)句引發(fā)一個(gè)異常,將它引發(fā)到當(dāng)前作用域之外。如果當(dāng)前作用域是一個(gè)函數(shù),就將異常傳遞給函數(shù)的調(diào)用方,讓調(diào)用方來(lái)處理。throw與return相似,表達(dá)式也相似,都會(huì)中止后面代碼的執(zhí)行。throw語(yǔ)句執(zhí)行將控制流轉(zhuǎn)到異常捕獲語(yǔ)句處理。這將導(dǎo)致throw語(yǔ)句下面相鄰語(yǔ)句不能執(zhí)行,而且會(huì)自動(dòng)回收當(dāng)前作用域中的局部變量。例如:throwindex;/弓I發(fā)一個(gè)int異常,index是一個(gè)int變量throwindexoutofrange;/弓I發(fā)一個(gè)constchar*異常throwinvalid_argument(denominatoriszero);/弓發(fā)invalid_a

16、rgument異常最后一個(gè)throw語(yǔ)句執(zhí)行過(guò)程是,先創(chuàng)建一個(gè)invalid_argument對(duì)象,然后再將該對(duì)象弓發(fā)到當(dāng)前作用域之外。throw與return的含義不同。一個(gè)函數(shù)的返回值表示正常執(zhí)行的結(jié)果,要作為顯式說(shuō)明的函數(shù)規(guī)范。throw語(yǔ)句雖然也能終止當(dāng)前函數(shù)的執(zhí)行,但表示不正常的執(zhí)行結(jié)果。一個(gè)函數(shù)只有一種返回類型,但可能弓發(fā)多種類型的異常。為了說(shuō)明一個(gè)函數(shù)可能引發(fā)哪些類型的異常,可用異常規(guī)范(exceptionspecification)來(lái)說(shuō)明,就是“throw(異常類型表)”。例如下面是一個(gè)求商函數(shù):doublequotient(intnumrator,intdenominator

17、)throw(invalid_argument)if(denominator=0)throwinvalid_argument(denominatoriszero);returndouble(numrator)/denominator;該函數(shù)的第一個(gè)形參除以第二個(gè)形參,返回商作為結(jié)果。該函數(shù)的原型中包含了異常規(guī)范:throw(invalidargument),說(shuō)明該函數(shù)的調(diào)用可能引發(fā)invalid_argument異常。函數(shù)體中檢查第二個(gè)形參(即除數(shù)),如果除數(shù)為0,就弓發(fā)該異常。盡管異常規(guī)范目前還起不到語(yǔ)法檢驗(yàn)的作用,但起碼能告知函數(shù)的調(diào)用方注意捕獲哪些類型的異常,而不是僅僅等待函數(shù)的返回值。

18、異常對(duì)函數(shù)設(shè)計(jì)具有重要作用。傳統(tǒng)的C函數(shù)設(shè)計(jì)不用異常。如果函數(shù)有多種結(jié)果,返回類型只能有一個(gè),就要添加形參來(lái)表示其它結(jié)果。添加的形參往往是指針類型,在調(diào)用時(shí)要提供變量地址作為實(shí)參,在調(diào)用返回之后再判斷得到什么結(jié)果。例如,一個(gè)求商函數(shù)可能設(shè)計(jì)如下:doublequotient(intnumrator,intdenominator,int*isValid)if(denominator=0)*isValid=0;/用0表示無(wú)效除數(shù)return0;*isValid=1;/用1表示有效除數(shù)returndouble(numrator)/denominator;上面函數(shù)中商作為返回值,添加了一個(gè)引用形參來(lái)表

19、示除數(shù)是否有效。另一種可行的C函數(shù)設(shè)計(jì)是返回一個(gè)int值,0表示無(wú)效除數(shù),1表示有效除數(shù),而將商作為形參,如下所示:intquotient(intnumrator,intdenominator,double*result)if(denominator=0)return0;*result=double(numrator)/denominator;return1;可以看出,傳統(tǒng)的C函數(shù)設(shè)計(jì)把除數(shù)為0作為一種特殊情形,用if語(yǔ)句加以判斷處理,需要更多的函數(shù)形參,導(dǎo)致函數(shù)定義復(fù)雜化。另一方面,調(diào)用方在調(diào)用函數(shù)返回之后,就要立即用一個(gè)if語(yǔ)句來(lái)判斷返回值是否為1,如為1,商才有效,如不為1,商無(wú)效。這對(duì)

20、調(diào)用方有一種強(qiáng)迫性,必須立即做出判斷,這將導(dǎo)致程序邏輯復(fù)雜化,而且難以清晰表達(dá)正常流程。異常是C+提供的一種新概念,表示了偏離正常流程的小概率事件。異常不應(yīng)該使正常流程的描述復(fù)雜化,也不應(yīng)該讓調(diào)用方忽視可能發(fā)生的異常。調(diào)用方可以選擇在適當(dāng)?shù)牡胤郊胁东@處理多種異常,就要用到try-catch語(yǔ)句。使用throw語(yǔ)句,應(yīng)注意以下要點(diǎn):根據(jù)當(dāng)前異常情形,應(yīng)選擇更準(zhǔn)確、更具體的異常類型來(lái)引發(fā),而避免引發(fā)抽象的類型。例如,如果在new申請(qǐng)內(nèi)存之后,如果發(fā)現(xiàn)返回空指針,此時(shí)應(yīng)引發(fā)OutOfMemory類型的異常,而不是NullPointer異常,也不是更抽象的runtime_error或者excepti

21、on。準(zhǔn)確具體的異常信息對(duì)于調(diào)用方的處理非常重要,否則就可能導(dǎo)致誤解。如果一個(gè)函數(shù)中使用throw語(yǔ)句引發(fā)異常到函數(shù)之外,應(yīng)該在函數(shù)原型中用異常規(guī)范準(zhǔn)確描述,即“throw(異常類型表)”,使調(diào)用方知道可能引發(fā)的異常類型,提醒調(diào)用方不要忽視。雖然throw語(yǔ)句可以在函數(shù)中任何地方執(zhí)行,但應(yīng)盡可能避免在構(gòu)造函數(shù)、析構(gòu)函數(shù)中使用throw語(yǔ)句,因?yàn)檫@將導(dǎo)致對(duì)象的構(gòu)建和撤銷過(guò)程中出現(xiàn)底層內(nèi)存錯(cuò)誤,可能會(huì)導(dǎo)致程序在捕獲到異常之前就被終止。后面15.8節(jié)將分析其原因。一般來(lái)說(shuō),異常發(fā)生總是有條件的,往往在一條if語(yǔ)句檢測(cè)到某個(gè)假設(shè)條件不成立時(shí),才用throw語(yǔ)句引發(fā)異常,以阻止下面代碼執(zhí)行。在一個(gè)函數(shù)中

22、無(wú)條件引發(fā)異常,只有一個(gè)理由,就是不想讓其它函數(shù)調(diào)用,例如,一些實(shí)體類的拷貝構(gòu)造函數(shù)和賦值操作函數(shù)如果不想被調(diào)用,就將這些函數(shù)設(shè)為私有,同時(shí)用一條throw語(yǔ)句避免本類其它函數(shù)執(zhí)行。千萬(wàn)不要認(rèn)為,只要我的編程中沒有throw語(yǔ)句就不會(huì)引發(fā)異常,沒有異常就是可靠的。你可以暫時(shí)忽略異常,但當(dāng)假設(shè)條件不滿足,異??倳?huì)發(fā)生。當(dāng)異常發(fā)生時(shí)你就不知道在何處出現(xiàn)異常,也不知道什么原因?qū)е庐惓?,更不知道如何處理能使程序繼續(xù)執(zhí)行。語(yǔ)句捕獲處理異常的語(yǔ)句是try-catch語(yǔ)句,一條try-catch語(yǔ)句由一個(gè)try子句(一條復(fù)合語(yǔ)句)和多個(gè)catch子句組成。一個(gè)catch子句包括一個(gè)異常類型及變量和一個(gè)異常處

23、理器(一條復(fù)合語(yǔ)句)。語(yǔ)法格式如下:try可能引發(fā)異常的語(yǔ)句序列;/受保護(hù)代碼catch(異常類型1異常變量1)處理代碼1;/異常處理器1catch(異常類型2異常變量2)處理代碼2;/異常處理器2.catch(.)處理代碼;/異常處理器其中,關(guān)鍵字try之后的一個(gè)復(fù)合語(yǔ)句稱為try子句。這個(gè)復(fù)合語(yǔ)句中的代碼被稱為受保護(hù)代碼,包含多條語(yǔ)句。受保護(hù)代碼描述正常的執(zhí)行流程,但這些語(yǔ)句的執(zhí)行卻可能引發(fā)異常。如果執(zhí)行沒有發(fā)生異常,try-catch語(yǔ)句就正常結(jié)束,開始執(zhí)行其下面語(yǔ)句。如果引發(fā)了某種類型的異常,就按catch子句順序逐個(gè)匹配異常類型,捕獲并處理該異常。如果異常被捕獲,而且處理過(guò)程中未引發(fā)

24、新的異常,try-catch語(yǔ)句就正常結(jié)束。如果異常未被捕獲,該異常就被引發(fā)到外層作用域。圖15.3表示了try-catch語(yǔ)句的組成結(jié)構(gòu)。圖語(yǔ)句的組成結(jié)構(gòu)一條語(yǔ)句執(zhí)行引發(fā)異常,有以下3種可能的原因:1、該語(yǔ)句是throw語(yǔ)句。2、調(diào)用函數(shù)引發(fā)了異常。3、表達(dá)式執(zhí)行引發(fā)了未命名的異常,如整數(shù)除數(shù)為0、掛空訪問(wèn)等例如下面try-catch語(yǔ)句,調(diào)用了前面介紹的求商函數(shù)quotient。tryTOC o 1-5 h zresult=quotient(n1,n2);/AcoutThequotientisresult;/B/.catch(invalid_argumentex)/Ccoutinvalid

25、_argument:ex.what();/DA行調(diào)用quotient函數(shù),如果沒有引發(fā)異常,就執(zhí)行B行,然后try-catch語(yǔ)句就執(zhí)行完畢。如果A行引發(fā)了某種異常,B行就不執(zhí)行,從C行開始匹配異常類型,因?yàn)锳行函數(shù)調(diào)用可能引發(fā)的異常類型正式catch子句要捕獲的異常類型invalid_argument,故此該異常對(duì)象就替代了ex形參,之后再執(zhí)行后面的一個(gè)復(fù)合語(yǔ)句,D行調(diào)用異常對(duì)象ex的成員函數(shù)得到錯(cuò)誤信息,然后打印出來(lái)。try-catch語(yǔ)句執(zhí)行完畢。無(wú)論是否發(fā)生異常,這個(gè)try-catch語(yǔ)句都能執(zhí)行完畢,下面語(yǔ)句都能執(zhí)行。異常是按其類型進(jìn)行捕獲處理的。一個(gè)catch子句僅捕獲一類異常。一

26、個(gè)catch子句由一個(gè)異常類型及變量和一個(gè)異常處理器(一條復(fù)合語(yǔ)句)構(gòu)成。異常類型及變量指明要捕獲的異常的類型,以及接受異常對(duì)象的變量。例如catch(invalid_argumentex),要捕獲的異常類型為invalid_argument,如果真的捕獲到該類異常,那么變量ex就持有這個(gè)異常對(duì)象,這個(gè)對(duì)象就是前面用throw語(yǔ)句引發(fā)出來(lái)的。有一種特殊的catch子句,就是catch(.),該子句能匹配任何類型的異常,包括未命名的異常,不過(guò)異常對(duì)象或值不能被變量捕獲,故此不能提供確切的錯(cuò)誤信息。在多個(gè)catch子句中,這種catch子句應(yīng)該排在最后。在執(zhí)行try子句中的受保護(hù)代碼時(shí),如果引發(fā)一

27、個(gè)異常,系統(tǒng)就到catch子句中尋找處理該異常類型的入口。這種尋找過(guò)程稱為異常類型匹配。按如下步驟進(jìn)行:由throw語(yǔ)句引發(fā)異常事件之后,系統(tǒng)依次檢查catch子句以尋找相匹配的處理異常事件入口。如果某個(gè)catch子句的異常類型說(shuō)明與被引發(fā)出來(lái)的異常事件類型相一致,該異常就被捕獲,然后執(zhí)行該子句的異常處理器代碼。如果有多個(gè)catch子句的異常類型相匹配,按照前后次序只執(zhí)行第一個(gè)匹配的異常處理代碼。因此較具體的派生類異常應(yīng)該在匹配在前,以提供最具體詳細(xì)的信息,而較抽象的基類異常應(yīng)該排在后面。若沒有找到任何相匹配的catch子句,該異常就被傳遞到外層作用域。如果外層作用域是函數(shù),就傳遞到函數(shù)的調(diào)用

28、方。一個(gè)異常的生命期從創(chuàng)建、初始化之后,被throw引發(fā)出來(lái),然后被某個(gè)catch子句捕獲,其生命期就結(jié)束了。一個(gè)異常從引發(fā)出來(lái)到被捕獲,可能穿越多層作用域或函數(shù)調(diào)用。如果到main函數(shù)都未被捕獲,將導(dǎo)致程序被迫終止。從圖15.3中可以看出,try-catch語(yǔ)句的執(zhí)行結(jié)果有兩個(gè):正常和異常。表15.1分析了try-catch語(yǔ)句的4種具體情形。表語(yǔ)句執(zhí)行結(jié)果序號(hào)結(jié)果具體情形1正常完畢受保護(hù)代碼未引發(fā)異常2正常完畢受保護(hù)代碼引發(fā)了異常,但異常被某個(gè)catch子句捕獲3異常退出受保護(hù)代碼引發(fā)了異常,但未被catch子句捕獲4異常退出受保護(hù)代碼引發(fā)了異常,而且被某個(gè)catch子句捕獲,但在異常處理

29、器中又引發(fā)了新的異常,或者用“throw;”語(yǔ)句把剛捕獲的異常又重新引發(fā)出來(lái)分析下面try-catch語(yǔ)句的可能結(jié)果:tryresult=quotient(n1,n2);coutThequotientisresult;/.catch(invalid_argumentex)coutinvalid_argument:ex.what();catch(logic_errorex)coutlogic_error:ex.what();catch(exceptionex)coutexception:ex.what();catch(.)coutsomeunexpectedexception;上面try子句中調(diào)

30、用了可能引發(fā)異常的函數(shù)quotient。這個(gè)try語(yǔ)句包含了4個(gè)catch子句,這4個(gè)catch子句的次序是較具體的派生類放在前面,較抽象的基類放在后面。最后一個(gè)catch子句可匹配捕獲任意類型的異常,但因得不到異常對(duì)象,故此不能提供更多信息。在一次執(zhí)行時(shí),如果引發(fā)異常,只能有一個(gè)catch子句捕獲處理該異常。由于最后一個(gè)catch子句能捕獲所有類型的異常,而且所有的異常處理器代碼中都不會(huì)引發(fā)異常,因此該try-catch語(yǔ)句的執(zhí)行結(jié)果是表中第1種或者第2種情形。對(duì)于try-catch語(yǔ)句的理解和應(yīng)用,應(yīng)注意以下幾點(diǎn)。try子句中的代碼,稱為受保護(hù)代碼,實(shí)際上是受到下面若干catch子句的保護(hù)

31、,使得try子句代碼可以放心去描述正常處理流程,而無(wú)需每執(zhí)行一步都要用if語(yǔ)句來(lái)判斷是否發(fā)生異常情形。并非try子句都可能引發(fā)異常,也并非catch子句要捕獲try子句所引發(fā)的所有異常,當(dāng)前函數(shù)只需捕獲自己能處理的異常。多個(gè)catch子句之間,不允許基類異常在前、派生類在后,否則將出現(xiàn)語(yǔ)法警告,這使得列在后面的派生類捕獲不到異常,而排在前面的基類先捕獲到了。try-catch語(yǔ)句僅適合處理異常,并不能將其作為正常流程控制。例.子3例15-1控制流程測(cè)試。#includevoidtestExcept(inti)tryif(i=1)throwcatchmewheni=1;/Aif(i=2)TOC

32、o 1-5 h zthrowi;/Bif(i=0)intd=(i+1)/i;/Ccoutdendl;/Dcouti=i;catch(inti)/Ecoutcatchanint:i;catch(char*ex)/Fcoutcatchastring:ex;catch(.)/Gcoutcatchanexceptionunknown;cout的下標(biāo)越界異常。標(biāo)準(zhǔn)模板庫(kù)STL提供的向量vectorvT是支持元素隨機(jī)訪問(wèn)的一種常用容器,它有兩種隨機(jī)訪問(wèn)形式:operator和at(),后者可引發(fā)out_of_range異常。#include#includeusingnamespacestd;voidmai

33、n()tryvectorvec(4);/Ainti=0;for(i=0;i4;i+)veci=i+1;for(i=0;i=4;i+)coutveci;coutendl;for(i=0;i=4;i+)coutvec.at(i)coutendl;catch(out_of_rangeex)coutoutofcatch(.)/B/Cnoexception/Dthrowexceptionwheni=4range:ex.what()endl;coutunexpectedn執(zhí)行程序,輸出如下:1234-336860191234outofrange:invalidvectorsubscript上面程序測(cè)試兩種

34、按下標(biāo)隨機(jī)訪問(wèn)元素的成員函數(shù)。A行先創(chuàng)建了一個(gè)向量,包含4個(gè)int元素。B行對(duì)這4個(gè)元素初始化。C行調(diào)用operator來(lái)訪問(wèn)元素,輸出第1行,當(dāng)下標(biāo)越界時(shí),并沒有引發(fā)任何異常,只是讀取的vec4元素的值是隨機(jī)值。D行調(diào)用at(intindex)來(lái)訪問(wèn)元素,輸出第2行。當(dāng)下標(biāo)越界時(shí),引發(fā)了out_of_range異常,而不會(huì)按非法下標(biāo)讀取值。例15-3除數(shù)為0的異常。在整數(shù)除法中,如果除數(shù)為0就引發(fā)底層未命名異常,因此有必要在除法執(zhí)行之前判斷除數(shù)是否為0,如果除數(shù)為0就引發(fā)一個(gè)命名的異常來(lái)通知調(diào)用方。編程如下:#include#includeusingnamespacestd;doublequ

35、otient(intnumrator,intdenominator)throw(invalid_argument)if(denominator=0)throwinvalid_argument(denominatoriszero);/Areturndouble(numrator)/denominator;voidmain()intn1,n2;doubleresult;coutn1n2)tryresult=quotient(n1,n2);coutThequotientisresult;TOC o 1-5 h zcatch(invalid_argumentex)/Bcoutinvalid_argum

36、ent:ex.what();catch(logic_errorex)/Ccoutlogic_error:ex.what();catch(exceptionex)/Dcoutexception:ex.what();catch(.)/Ecoutsomeunexpectedexception;cout和vexception中分別提供了terminate()函數(shù),前者是老版本,作為全局函數(shù),后者是新版本,定義在std命名空間之中。在發(fā)生下面情形之一時(shí)將自動(dòng)執(zhí)行terminate()函數(shù):1、引發(fā)異常最終未能捕獲。2、析構(gòu)函數(shù)在系統(tǒng)堆棧釋放時(shí)引發(fā)了異常。3、在引發(fā)某個(gè)異常之后系統(tǒng)堆棧遭破壞。缺省的ter

37、minate函數(shù)將調(diào)用abort函數(shù),但abort函數(shù)不執(zhí)行清理而簡(jiǎn)單終止程序,因此常常需要自行定義一個(gè)函數(shù),作為terminate函數(shù)調(diào)用的函數(shù),這要先準(zhǔn)備一個(gè)無(wú)參且無(wú)返回的函數(shù)f,然后調(diào)用set_terminate(f),將函數(shù)f作為終止處理器。例15-4terminate函數(shù)的例子。#include#includeusingnamespacestd;voidterm_func()/Acoutterm_func()wascalledbyterminate().n;/.cleanuptasksperformedhere/Ifthisfunctiondoesnotexit,abortiscal

38、led.exit(-1);voidmain()inti=10,j=0,result;set_terminate(term_func);/Btryif(j=0)throwDividebyzero!;/Celseresult=i/j;catch(int)coutCaughtanintegerexception.n;cout中的相關(guān)定義如下:typedefvoid(*terminate_handler)();/函數(shù)指針類型,終止處理器terminate_handlerset_terminate(terminate_handlerph)throw();voidterminate();頭一行說(shuō)明了一種函

39、數(shù)指針的類型名,第二行說(shuō)明了一個(gè)函數(shù)set_terminate,將一個(gè)函數(shù)ph說(shuō)明為新的終止處理器。最后一行是異常處理器函數(shù),缺省將調(diào)用abort函數(shù)。C行引發(fā)的異常類型為constchar*,顯然不能被下面的catch子句捕獲,該異常將導(dǎo)致程序終止,將執(zhí)行terminate函數(shù),因?yàn)锽行設(shè)置了新的終止處理函數(shù)term_func,那么新的函數(shù)得到執(zhí)行。通常情況下,設(shè)置終止函數(shù)的目的是釋放資源,然后調(diào)用exit函數(shù)來(lái)終止程序。標(biāo)準(zhǔn)C+還支持意外處理器unexpectedhandler,但VC+6版本并不支持。15.擴(kuò)5展新的異常類型雖然前面圖15.2給出了一個(gè)異常類型架構(gòu),但經(jīng)常需要擴(kuò)展自己的異

40、常類型。例如,雖然out_of_range類能用于說(shuō)明下標(biāo)越界,但未說(shuō)明發(fā)生異常的下標(biāo)究竟值是什么。再如,前面例子中除數(shù)為0的異常使用了invalid_argument類,而實(shí)際上除數(shù)為0可能有多種情形,而不一定都作為函數(shù)實(shí)參,因此有必要自行定義除數(shù)為0的異常類。圖15.4給出了一組擴(kuò)展的異常類型。擴(kuò)展異常類主要是以logic_error和runtime_error為基類來(lái)定義派生類。下面構(gòu)造了一個(gè)頭文件exceptions.h,包含了一組常用的異常類。#ifndefEXCEPTIONS#defineEXCEPTIONS#include#includeusingnamespacestd;/下標(biāo)

41、越界,記錄下標(biāo)classIndex_out_of_range:publicout_of_rangeconstintindex;public:Index_out_of_range(intindex1,conststring&what_arg):index(index1),out_of_range(what_arg)intgetIndex()constreturnindex;/除數(shù)為0classDivideByZero:publicruntime_errorpublic:DivideByZero(conststring&what_arg):runtime_error(what_arg);/空指針c

42、lassNullPointer:publicruntime_errorpublic:NullPointer(conststring&what_arg):runtime_error(what_arg);/無(wú)可用內(nèi)存classOutOfMemory:publicruntime_errorpublic:OutOfMemory(conststring&what_arg):runtime_error(what_arg);/一般IO異常的基類classIOException:publicruntime_errorpublic:IOException(conststring&what_arg):runtim

43、e_error(what_arg);/打開文件失敗,記錄文件名/可能是要讀的文件不存在,也可能是要寫的文件不能創(chuàng)建classOpenFileException:publicIOExceptionpublic:OpenFileException(conststring&filename):IOException(filename);/讀取文件到特定位置時(shí)轉(zhuǎn)換失敗,記錄文件出錯(cuò)位置/出錯(cuò)位置可以是文本文件的數(shù)據(jù)位置,第n項(xiàng)出錯(cuò)/也可以是二進(jìn)制文件的字節(jié)位置,第n個(gè)字節(jié)出錯(cuò)classReadFileFail:publicIOExceptionconstlongerrPos;public:ReadFi

44、leFail(longpos,conststring&what_arg):errPos(pos),IOException(what_arg)constlonggetErrPos()constreturnerrPos;#endif讀者可自行擴(kuò)展合適的派生類,以適合軟件開發(fā)的具體需要。下面部分例子要使用這些異常類型。15.異6常類型的應(yīng)用利用擴(kuò)展的異常類型,就可對(duì)許多已有程序進(jìn)行改進(jìn)。例如前面矩陣類模板TMatrixvT中,有一個(gè)公有成員函數(shù)elemAt如下:templateT&TMatrix:elemAt(intr,intc)/按下標(biāo)訪問(wèn)元素if(r=row)throwr;/行下標(biāo)越界,引發(fā)in

45、t異常if(c=col)throwc;/列下標(biāo)越界,引發(fā)int異常returndprc;原先是引發(fā)int類型異常,這容易與其它異常混淆?,F(xiàn)在就可以使用更明確的Index_out_of_range類型的異常。上面2條throw語(yǔ)句就可以分別改為:throwIndex_out_of_range(r,rowindexinelemAt(int,int);throwIndex_out_of_range(c,colindexinelemAt(int,int);TMatrix模板中另一個(gè)公有成員函數(shù)operator()(intr,intc)調(diào)用了elemAt函數(shù),所以operator()(intr,intc

46、)函數(shù)也會(huì)引發(fā)下標(biāo)越界異常。這些函數(shù)都沒有顯式說(shuō)明異常規(guī)范:throw(Index_out_of_range)這是由于VC+6沒有對(duì)異常規(guī)范進(jìn)行語(yǔ)法檢查(Java語(yǔ)言要求明確的異常規(guī)范,否則語(yǔ)法編譯出錯(cuò))。不過(guò)規(guī)范的設(shè)計(jì)應(yīng)該顯式說(shuō)明每個(gè)函數(shù)的異常規(guī)范,以提示調(diào)用方可能引發(fā)哪些異常,避免遺忘捕獲處理。例15-5設(shè)計(jì)一個(gè)函數(shù)從一個(gè)文本文件中讀取多個(gè)浮點(diǎn)數(shù),放入一個(gè)向量vector中,顯示各元素,給出元素的個(gè)數(shù),并按升序排序。要讀取的文本文件包含任意多的浮點(diǎn)數(shù),用分隔符分開,例如:11.27.83.4這個(gè)例子將演示多種異常類型的引發(fā)和處理。編程如下:#include#include#include#

47、includeexceptions.husingnamespacestd;voidgetVectorFromFile(char*filename,vector&vfs)throw(NullPointer,OpenFileException,ReadFileFail)if(filename=NULL)throwNullPointer(filenameisnull);:ifstreamifs(filename,ios:in|ios:nocreate);if(!ifs)stringmsg=openfile:;msg+=filename;msg+=failforread;throwOpenFileEx

48、ception(msg);floatf;while(!ifs.eof()ifsf;if(ifs.fail()stringmsg=readfilefail:;msg+=filename;throwReadFileFail(vfs.size(),msg);vfs.push_back(f);ifs.close();return;voidmain()trycharfilename200;coutfilename;vectorvf;getVectorFromFile(filename,vf);cout元素個(gè)數(shù):vf.size():endl;for(inti=0;ivf.size();i+)coutvf.

49、at(i);coutendl;sort(vf.begin(),vf.end();coutaftersortedn;for(i=0;ivf.size();i+)coutvf.at(i);coutendl;catch(NullPointerex)coutex.what()endl;catch(OpenFileExceptionex)coutex.what()endl;catch(ReadFileFailex)coutex.what()atex.getErrPos()itemn;catch(out_of_rangeex)coutindexoutex.what()endl;catch(exceptio

50、nex)coutex.what()endl;catch(.)coutexceptionunknown引用作為結(jié)果。該函數(shù)可能引發(fā)3種命名異常,用異常規(guī)范throw說(shuō)明,以提示調(diào)用方。該函數(shù)直接引發(fā)3種類型的異常:1、檢查形參指針是否為空,可能引發(fā)NullPointer異常;2、打開文件,可能引發(fā)OpenFileException異常,保存了出錯(cuò)的文件名;3、讀浮點(diǎn)數(shù),可能引發(fā)ReadFileFail異常,保存了文件讀錯(cuò)的位置。在函數(shù)getVectorFromFile執(zhí)行過(guò)程中只要引發(fā)任何一種異常,就不能得到結(jié)果。主函數(shù)中使用try-catch語(yǔ)句來(lái)完成計(jì)算并捕獲處理各種異常。先輸入一個(gè)文件名,

51、并說(shuō)明一個(gè)vectorvfloat變量,再調(diào)用函數(shù)getVectorFromFile來(lái)得到結(jié)果,下面就是顯示、排序、再顯示。其中在調(diào)用at(i)函數(shù)時(shí)可能引發(fā)out_of_range異常。執(zhí)行程序,在第1行輸入一個(gè)文件名array.txt,輸出如下:inputfilenametoread:array.txt元素個(gè)數(shù):12:aftersorted讀者可自行改變輸入或改變文本文件,引入各種錯(cuò)誤,看程序運(yùn)行是否能正確判斷各種異常。例如:用NULL值來(lái)調(diào)用函數(shù),看是否導(dǎo)致NullPointerException。輸入錯(cuò)誤的文件名是否會(huì)導(dǎo)致OpenFileException。把某個(gè)浮點(diǎn)數(shù)的字符該為字符,

52、看是否導(dǎo)致ReadFileFail。try子句中的代碼描述了正常執(zhí)行的邏輯,而各種異常的捕獲處理都用catch子句描述。這樣就能將正常流程與異常處理分割開,不僅提高了程序的可讀性和可維護(hù)性,而且增強(qiáng)了應(yīng)對(duì)多種錯(cuò)誤的能力,提高了編程可靠性。15.函7數(shù)設(shè)計(jì)中的異常處理在函數(shù)設(shè)計(jì)中何時(shí)要用到異常?有以下3個(gè)原則:1、遇到小概率事件,應(yīng)考慮使用異常。一種小概率事件往往就是一種異常情形,例如,函數(shù)的指針形參在調(diào)用時(shí)卻得到了空指針實(shí)參。再例如,要輸入一個(gè)浮點(diǎn)數(shù),但實(shí)際輸入錯(cuò)誤。小概率事件也意味著在可靠性要求不高的前提下可以推遲處理、甚至忽略。前面很多例子都有這樣一個(gè)前提,即小概率事件不會(huì)發(fā)生。反之,如果

53、不是小概率事件,就不適合用異常。例如,讀文件到文件尾eof判斷,就不適合將讀到文件尾作為一種異常來(lái)處理,它不是小概率事件,因?yàn)槊恳淮巫x取都應(yīng)判斷是否到達(dá)文件尾。2、遇到某種情形,根據(jù)當(dāng)前信息不能確定應(yīng)該如何處理,應(yīng)考慮用異常來(lái)通知調(diào)用方處理。例如,一個(gè)函數(shù)從文本文件中讀浮點(diǎn)數(shù)序列,文件名由形參提供,假如按調(diào)用方提供的文件名打開文件失敗,應(yīng)如何處理?此時(shí)合理的辦法就是告訴調(diào)用方,這個(gè)文件名打開失敗了,由調(diào)用方來(lái)決定是換一個(gè)文件名,還是放棄。反之,對(duì)于某種情形,如果函數(shù)可以處理而且不違背約定,那么這種情形就不適合作為異常。例如對(duì)于堆棧stack操作pop,只有先判斷堆棧不為空,才能彈出pop元素。

54、堆棧為空這種情形不適合作為異常。3、向調(diào)用方報(bào)告的某種結(jié)果的描述比較復(fù)雜,就應(yīng)考慮使用異常。傳統(tǒng)的C語(yǔ)言編程常用不同的int值來(lái)表示各種錯(cuò)誤。例如一個(gè)函數(shù)從文本文件中讀浮點(diǎn)數(shù)序列,可以讓該函數(shù)返回一個(gè)int值,而且約定返回0表示正常,-1表示實(shí)參空指針,-2表示打開文件失敗,-3表示讀取數(shù)據(jù)失敗等。但返回-2時(shí),還應(yīng)告知打開失敗的文件名。當(dāng)返回-3時(shí),不僅要告知文件名,還應(yīng)告知導(dǎo)致讀取失敗的具體位置,即第幾個(gè)元素讀取失敗,這樣才方便調(diào)用方有效解決問(wèn)題,此時(shí)就需要用異常來(lái)詳細(xì)描述。在一個(gè)函數(shù)設(shè)計(jì)中,要調(diào)用一個(gè)可能引發(fā)某種異常的函數(shù)時(shí),有哪些處理方式?當(dāng)前函數(shù)有下面4種選擇:1、捕獲該異常并進(jìn)行處

55、理,使自己的調(diào)用方不需要捕獲處理該異常。2、捕獲該異常,在處理代碼中轉(zhuǎn)換為另一種異常,再引發(fā)出去,讓調(diào)用方來(lái)捕獲處理新的異常。3、捕獲該異常,處理(可能是記錄異常發(fā)生),再將捕獲到的異常引發(fā)出去,讓外層調(diào)用方來(lái)捕獲處理。在處理代碼中用不帶表達(dá)式的throw語(yǔ)句可以轉(zhuǎn)發(fā)已捕獲到的異常。4、不捕獲該異常,讓外層調(diào)用方來(lái)捕獲處理??赡苁菦]有try-catch語(yǔ)句,也可能有try-catch但沒有catch子句能匹配所發(fā)生的異常類型。應(yīng)采取何種處理方式取決于當(dāng)前函數(shù)所承擔(dān)的異常處理的責(zé)任。第1種方式完全承擔(dān)了該種異常處理的責(zé)任,使外層調(diào)用方可以放心調(diào)用而無(wú)需關(guān)心會(huì)發(fā)生此類異常。第4種方式則完全不承擔(dān)責(zé)

56、任,調(diào)用方必須考慮如何處理間接引發(fā)的異常。第2種和第3種方式介于兩者之間,承擔(dān)了部分責(zé)任,能捕獲處理異常,也能引發(fā)異常。無(wú)論采用哪一種方式,函數(shù)的異常規(guī)范應(yīng)告知調(diào)用方可能會(huì)引發(fā)哪些類型的異常。這應(yīng)該是函數(shù)約定的一個(gè)重要部分。例15-6異常處理流程的例子#include#includeusingnamespacestd;floatgetValue(inti)/Atryif(i0)throwindexisoutofrange;/Bthrowchar*if(i=0)throw3.14f;/Cthrowfloatif(i=1)throwi;/Dthrowintif(i=2)throw2.718;/Et

57、hrowdoublecoutintryblock,i=iendl;catch(intindex)/Fcatchintcoutcatchintexception:indexendl;catch(floatf)coutcatchfloatexception:fendl;throw;/Gthrowfloatcatch(char*msg)coutcatchchar*exception:msgendl;throwexception(msg);/Hthrowexceptioncoutbelowtry-catch,i=iendl;returni+1;voidmain()for(inti=-1;i=3;i+)

58、tryfloatf=getValue(i);coutf=fendl;catch(floatf)coutmain:catchafloatexception:fendl;catch(doubled)coutmain:catchadoubleexception:dendl;catch(exceptionex)coutmain:catchanexception:ex.what()endl;catch(.)coutcatchanexceptionunknownendl;執(zhí)行程序,輸出如下(行號(hào)是為了方便解釋而加入的):catchchar*exception:indexisoutofrangemain:c

59、atchanexception:indexisoutofrangecatchfloatexception:3.14main:catchafloatexception:3.14catchintexception:1belowtry-catch,i=1f=2main:catchadoubleexception:2.718intryblock,i=3belowtry-catch,i=3f=4A行定義的函數(shù)沒有顯式給出異常規(guī)范。在函數(shù)體中的try子句中用throw引發(fā)了4類異常,后面的3個(gè)catch子句分別捕獲了3類異常,但異常處理器代碼中又引發(fā)了異常。這些異常的引發(fā)、捕獲、再引發(fā)的關(guān)系如下:i=-1

60、;引發(fā)char*異常,被捕獲,再引發(fā)exception異常出來(lái)。i=0;引發(fā)float異常,被捕獲,再用throw;轉(zhuǎn)發(fā)float異常出來(lái)。i=1;引發(fā)int異常,被捕獲,沒有再引發(fā)其它異常出來(lái)。i=2;引發(fā)double異常,沒有被捕獲。這樣可以知道getValue函數(shù)的異常規(guī)范為throw(exception,float,double)。在main函數(shù)中用i=-1到3來(lái)調(diào)用該函數(shù),并用try-catch語(yǔ)句來(lái)捕獲所有這些異常。輸出情況如下:i=-1,輸出前2行。i=0,輸出第3、4行。i=1,輸出第5、6、7行。i=2,輸出第8行。i=3,無(wú)異常,輸出第9、10、11行。能否在捕獲異常之后再

溫馨提示

  • 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)論