綜合測驗
章節回顧
異常處理提供了一種機制,可以將錯誤或其他異常情況的處理與代碼的典型控制流分離。這允許更自由地處理在給定情況下何時以及如何處理最有用的錯誤,從而減輕返回代碼引起的許多(如果不是全部)混亂。
一個throw句用來引發異常。 try塊查找在其中編寫或調用的代碼拋出的異常。這些異常被路由到catch塊,這些塊捕獲特定類型的異常(如果它們匹配)並處理它們。默認情況下,捕獲的異常被視爲已處理。
異常情況會立即處理。如果引發異常,控制將跳轉到最近的封閉try塊,查找可以處理異常的catch處理程序。如果沒有找到try塊或沒有catch塊匹配,則堆棧將被展開直到找到一個處理程序。如果在展開整個堆棧之前沒有找到處理程序,程序將以未處理的異常錯誤終止。
可以拋出任何數據類型的異常,包括類。
可以將Catch塊配置爲捕獲特定數據類型的異常,或者可以使用省略號(…)設置catch-all處理程序。捕獲基類引用的catch塊也將捕獲派生類的異常。標準庫拋出的所有異常都是從std :: exception類(它位於異常頭中)派生的,因此通過引用捕獲std :: exception將捕獲所有標準庫異常。what()成員函數可用於確定拋出了什麼類型的std :: exception。
在catch塊內部,可能會拋出新的異常。因爲這個新異常被拋出與該catch塊關聯的try塊之外,所以它不會被它所引發的catch塊捕獲。可以通過使用關鍵字throw本身從catch塊中重新拋出異常。不要使用捕獲的異常變量重新拋出異常,否則可能導致對象切片。
函數try塊爲您提供了一種方法來捕獲函數或關聯的成員初始化列表中發生的任何異常。這些通常僅用於派生類構造函數。
你永遠不應該從析構函數中拋出異常。
最後,異常處理確實有成本。在大多數情況下,使用異常的代碼運行速度會稍慢,處理異常的代價非常高。您應該只使用異常來處理異常情況,而不是正常的錯誤處理情況(例如無效輸入)。
Quiz Time:
1)編寫一個Fraction類,它有一個帶分子和分母的構造函數。如果用戶傳入的分母爲0,則拋出類型爲std :: runtime_error的異常(包含在stdexcept頭中)。在主程序中,要求用戶輸入兩個整數。如果“分數”有效,則打印分數。如果Fraction無效,則捕獲std :: exception,並告訴用戶他們輸入了無效的分數。
以下是程序運行的輸出:
Enter the numerator: 5
Enter the denominator: 0
Your fraction has an invalid denominator.
解決方案
#include <iostream>
#include <stdexcept> //std::runtime_error
class Fraction
{
private:
int m_numerator = 0;
int m_denominator = 1;
public:
Fraction(int numerator = 0, int denominator = 1) :
m_numerator(numerator), m_denominator(denominator)
{
if (m_denominator == 0)
throw std::runtime_error("Invalid denominator");
}
friend std::ostream& operator<<(std::ostream& out, const Fraction &f1);
};
std::ostream& operator<<(std::ostream& out, const Fraction &f1)
{
out << f1.m_numerator << "/" << f1.m_denominator;
return out;
}
int main()
{
std::cout << "Enter the numerator: ";
int numerator;
std::cin >> numerator;
std::cout << "Enter the denominator: ";
int denominator;
std::cin >> denominator;
try
{
Fraction f(numerator, denominator);
std::cout << "Your fraction is: " << f << '\n';
}
catch (std::exception&)
{
std::cout << "Your fraction has an invalid denominator.\n";
}
return 0;
}