你調用函數時,程序的控制權最終還會返回到函數的調用處,但是當你拋出一個異常時,控制權永遠不會回到拋出異常的地方。 把一個對象傳遞給函數或一個對象調用虛擬函數與把一個對象做為異常拋出,這之間有三個主要區別。 第一、異常對象在傳遞時總被進行拷貝;當通過傳值方式捕獲時,異常對象被拷貝了兩次。對象做為參數傳遞給函數時不一定需要被拷貝。第二、對象做為異常被拋出與做為參數傳遞給函數相比,前者類型轉換比後者要少(前者只有兩種轉換形式)。 最後一點,catch 子句進行異常類型匹配的順序是它們在源代碼中出現的順序,第一個類型匹配成功的 catch 將被用來執行。當一個對象調用一個虛擬函數時,被選擇的函數位於與對象類型匹配最佳的類裡,即使該類不是在源代碼的最前頭。 [cpp] #include <iostream> using namespace std; class Base { public: Base() { cout << "constructor" << endl; } ~Base() { cout << "destructor" << endl; } Base(const Base& m) { cout << "copy constructor" << endl; pInt = m.pInt; } void Message() {cout << "Base::Message" <<endl;} private: int pInt; }; class SubClass: public Base { public: SubClass() { cout << "constructor_sub" << endl; } ~SubClass(){ cout << "destructor_sub" << endl; } SubClass(const SubClass& ) { cout << "copy constructor_sub" << endl; } void Message() {cout << "SubClass::Message" <<endl;} private: }; int main() { int iTemp = 0; try { throw iTemp; } catch (double d) { cout << "double" << endl; } catch (int i) { cout << "int" << endl; } int* piTemp = NULL; try { throw piTemp; } catch (void* e) { cout << "void*" << endl; } catch (int* i) { cout << "int* " << endl; } SubClass n; try { throw n; } catch (Base& e) { e.Message(); //throw; //throw e; } catch (SubClass& ex) { e.Message(); } Base m; //Base* m = new Base(); try { throw m; } catch (Base e) { cout << "Base" << endl; } // catch (Base& e) // { // cout << "Base&" << endl; // } // catch (const Base& e) // { // cout << "const Base&" << endl; // } // catch (Base* e) // { // e->Message(); // delete e; // } } 第一部分throw iTemp;輸出:cout << "int" << endl; 對應上面的第二種情況,異常傳遞的類型如果是基礎類型的話不能進行隱式轉換。 第二部分throw piTemp;輸出:cout << "void*" << endl;對應上面的第二種情況,說明如果是異常拋出指針的話,catch參數可以被隱式轉換為void*指針。 第三部分throw n;輸出: constructor constructor_sub constructor copy constructor_sub Base::Message destructor_sub destructor 對應上面的第二種情況,說明在異常捕獲中,子類異常可以通過基類參數捕獲到。 對應上面的第三種情況,說明捕獲的順序是代碼中出現的順序。 把注釋掉的//throw; //throw e;兩句分別打開,運行結果確是一樣的,跟書中描述不盡相同。理論上講throw應該拋出的時subclass類型的異常。 最後一部分主要是驗證異常參數傳值,傳引用和傳指針的區別。通過程序結果可以看出,不論是傳值還是傳引用,都會進行拷貝構造,不同之處為傳值會進行兩次拷貝構造。不過在傳指針時,確沒有進行拷貝構造函數的調用。和函數參數穿指針一樣。但是需要注意的是,異常處理有可能會跟異常拋出位置不是同一個作用域,那樣拋指針異常的時候,有可能會造成異常洩露,所以我在最後顯示調用delete e;釋放資源。