拋出(Throw)--> 檢測(Try) --> 捕獲(Catch)
異常必須顯式地拋出,才能被檢測和捕獲到;如果沒有顯式的拋出,即使有異常也檢測不到。throw exceptionData;
exceptionData 是“異常數據”的意思,它可以包含任意的信息,完全有程序員決定。exceptionData 可以是 int、float、bool 等基本類型,也可以是指針、數組、字符串、結構體、類等聚合類型,請看下面的例子:
char str[] = "http://c.biancheng.net";
char *pstr = str;
class Base{};
Base obj;
throw 100; //int 類型
throw str; //數組類型
throw pstr; //指針類型
throw obj; //對象類型
#include <iostream>
#include <cstdlib>
using namespace std;
//自定義的異常類型
class OutOfRange{
public:
OutOfRange(): m_flag(1){ };
OutOfRange(int len, int index): m_len(len), m_index(index), m_flag(2){ }
public:
void what() const; //獲取具體的錯誤信息
private:
int m_flag; //不同的flag表示不同的錯誤
int m_len; //當前數組的長度
int m_index; //當前使用的數組下標
};
void OutOfRange::what() const {
if(m_flag == 1){
cout<<"Error: empty array, no elements to pop."<<endl;
}else if(m_flag == 2){
cout<<"Error: out of range( array length "<<m_len<<", access index "<<m_index<<" )"<<endl;
}else{
cout<<"Unknown exception."<<endl;
}
}
//實現動態數組
class Array{
public:
Array();
~Array(){ free(m_p); };
public:
int operator[](int i) const; //獲取數組元素
int push(int ele); //在末尾插入數組元素
int pop(); //在末尾刪除數組元素
int length() const{ return m_len; }; //獲取數組長度
private:
int m_len; //數組長度
int m_capacity; //當前的內存能容納多少個元素
int *m_p; //內存指針
private:
static const int m_stepSize = 50; //每次擴容的步長
};
Array::Array(){
m_p = (int*)malloc( sizeof(int) * m_stepSize );
m_capacity = m_stepSize;
m_len = 0;
}
int Array::operator[](int index) const {
if( index<0 || index>=m_len ){ //判斷是否越界
throw OutOfRange(m_len, index); //拋出異常(創建一個匿名對象)
}
return *(m_p + index);
}
int Array::push(int ele){
if(m_len >= m_capacity){ //如果容量不足就擴容
m_capacity += m_stepSize;
m_p = (int*)realloc( m_p, sizeof(int) * m_capacity ); //擴容
}
*(m_p + m_len) = ele;
m_len++;
return m_len-1;
}
int Array::pop(){
if(m_len == 0){
throw OutOfRange(); //拋出異常(創建一個匿名對象)
}
m_len--;
return *(m_p + m_len);
}
//打印數組元素
void printArray(Array &arr){
int len = arr.length();
//判斷數組是否為空
if(len == 0){
cout<<"Empty array! No elements to print."<<endl;
return;
}
for(int i=0; i<len; i++){
if(i == len-1){
cout<<arr[i]<<endl;
}else{
cout<<arr[i]<<", ";
}
}
}
int main(){
Array nums;
//向數組中添加十個元素
for(int i=0; i<10; i++){
nums.push(i);
}
printArray(nums);
//嘗試訪問第20個元素
try{
cout<<nums[20]<<endl;
}catch(OutOfRange &e){
e.what();
}
//嘗試彈出20個元素
try{
for(int i=0; i<20; i++){
nums.pop();
}
}catch(OutOfRange &e){
e.what();
}
printArray(nums);
return 0;
}
運行結果:[ ]運算符來訪問數組元素,如果下標過小或過大,就會拋出異常(第53行代碼);在拋出異常的同時,我們還記錄了當前數組的長度和要訪問的下標。double func (char param) throw (int);
這條語句聲明了一個名為 func 的函數,它的返回值類型為 double,有一個 char 類型的參數,並且只能拋出 int 類型的異常。如果拋出其他類型的異常,try 將無法捕獲,只能終止程序。double func (char param) throw (int, char, exception);
如果函數不會拋出任何異常,那麼( )中什麼也不寫:
double func (char param) throw ();
如此,func() 函數就不能拋出任何類型的異常了,即使拋出了,try 也檢測不到。
class Base{
public:
virtual int fun1(int) throw();
virtual int fun2(int) throw(int);
virtual string fun3() throw(int, string);
};
class Derived:public Base{
public:
int fun1(int) throw(int); //錯!異常規范不如 throw() 嚴格
int fun2(int) throw(int); //對!有相同的異常規范
string fun3() throw(string); //對!異常規范比 throw(int,string) 更嚴格
}
//錯!定義中有異常規范,聲明中沒有
void func1();
void func1() throw(int) { }
//錯!定義和聲明中的異常規范不一致
void func2() throw(int);
void func2() throw(int, bool) { }
//對!定義和聲明中的異常規范嚴格一致
void func3() throw(float, char*);
void func3() throw(float, char*) { }
#include <iostream>
#include <string>
#include <exception>
using namespace std;
void func()throw(char*, exception){
throw 100;
cout<<"[1]This statement will not be executed."<<endl;
}
int main(){
try{
func();
}catch(int){
cout<<"Exception type: int"<<endl;
}
return 0;
}
在 GCC 下,這段代碼運行到第 7 行時程序會崩潰。雖然 func() 函數中發生了異常,但是由於 throw 限制了函數只能拋出 char*、exception 類型的異常,所以 try-catch 將捕獲不到異常,只能交給系統處理,終止程序。Exception type: int,這說明異常被成功捕獲了。在 Visual C++ 中使用異常規范雖然沒有語法錯誤,但是也沒有任何效果,Visual C++ 會直接忽略異常規范的限制,函數可以拋出任何類型的異常。