1. 概念
异常(exception)是程序的运行期间 出现的问题,因此程序的语法没有问题,但是逻辑出现了问题。
例如之前的容器越界问题:

程序一旦抛出了异常但是每一级都没有正确处理,就会造成程序运行的崩溃。
处理异常的方式有两种:
- 向上级抛出异常
- 直接捕获异常
2. 抛出异常
可以使用throw关键字在代码的任何位置抛出异常对象,这个异常对象理论上可以是任何类型,异常对象会在程序的调用层级中逐层传递,直到主函数。如果主函数中仍然不正确处理异常,则会运行终止。
#include <iostream>`
`using namespace std;`
`double divide(double a,double b)`
`{`
` // 定义抛出异常的规则`
` if(b == 0)`
` throw "除数为0!!!!!"; // const char*`
` return a/b;`
`}`
`double add(double a,double b)`
`{`
` return a+b;`
`}`
`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
` double x = add(a,b);`
` double y = divide(x,b);`
` cout << y << endl;`
`}`
`int main()`
`{`
` calculate(3,0);`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
3. 捕获异常
捕获异常使用try和catch代码块配合使用,其中try代码块用于尝试执行一段有可能出现异常抛出的代码,这段代码越少越好。
try代码块在执行的过程中,可能出现以下几种情况:

2.1情况代码
#include <iostream>`
`using namespace std;`
`double divide(double a,double b)`
`{`
` // 定义抛出异常的规则`
` if(b == 0)`
` throw "除数为0!!!!!"; // const char*`
` return a/b;`
`}`
`double add(double a,double b)`
`{`
` return a+b;`
`}`
`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
` double x = add(a,b);`
` double y = divide(x,b);`
` cout << y << endl;`
`}`
`int main()`
`{`
` try`
` {`
` calculate(3,0);`
` cout << "这句话不会得到执行" << endl;`
` }catch(const char* e)`
` {`
` cout << "异常的弥补措施" << e << endl;`
` }`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
2.2 捕获失败
#include <iostream>`
`using namespace std;`
`double divide(double a,double b)`
`{`
` // 定义抛出异常的规则`
` if(b == 0)`
` throw "除数为0!!!!!"; // const char*`
` return a/b;`
`}`
`double add(double a,double b)`
`{`
` return a+b;`
`}`
`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
` double x = add(a,b);`
` double y = 0;`
` try`
` {`
` y = divide(x,b); // 抛出const char*类型异常`
` cout << "这句话不会执行" << endl;`
` }catch(string s) // 捕获的却是string类型,不匹配,相当于没捕获,直接抛到上级`
` {`
` cout << "这里弥补措施也不会执行" << endl;`
` }`
` cout << y << endl;`
`}`
`int main()`
`{`
` calculate(3,0);`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
上面的代码还有一次捕获的机会,例如可以在calculate调用的位置再次捕获。
#include <iostream>`
`using namespace std;`
`double divide(double a,double b)`
`{`
` // 定义抛出异常的规则`
` if(b == 0)`
` throw "除数为0!!!!!"; // const char*`
` return a/b;`
`}`
`double add(double a,double b)`
`{`
` return a+b;`
`}`
`/**`
` * @brief calculate 随便设计了一个计算规则`
` * @param a`
` * @param b`
` */`
`void calculate(double a,double b)`
`{`
` double x = add(a,b);`
` double y = 0;`
` try`
` {`
` y = divide(x,b); // 抛出const char*类型异常`
` cout << "这句话不会执行" << endl;`
` }catch(string s) // 捕获的却是string类型,不匹配,相当于没捕获,直接抛到上级`
` {`
` cout << "这里弥补措施也不会执行" << endl;`
` }`
` cout << y << endl;`
`}`
`int main()`
`{`
` try`
` {`
` calculate(3,0);`
` }catch(const char* e)`
` {`
` cout << "捕获成功!" << e << endl;`
` }`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
4. 标准异常族
C++已经预定义了一些异常的类型,使用前需要引入头文件#include <stdexcept>:


5. 自定义异常
实际开发中,往往会自定义一些异常类型,此时就需要通过继承加入标准异常族。
#include <iostream>`
`#include <stdexcept> // 标准异常族`
`using namespace std;`
`/**`
` * @brief The ZeroException class`
` * 自定义异常类,继承了内置的异常基类`
` */`
`class ZeroException:public exception`
`{`
`public:`
` // throw()表示异常规格说明,告诉编译器此函数安全,不会出现异常`
` const char* what() const throw()`
` {`
` return "除数为0!!!!!";`
` }`
`};`
`double divide(double a,double b)`
`{`
` if(b == 0)`
` throw ZeroException(); // 抛出自定义异常`
` return a/b;`
`}`
`int main()`
`{`
` try`
` {`
` divide(3,0);`
` }catch(const ZeroException& e)`
` {`
` cout << "做出一些弥补的措施" << endl;`
` cout << e.what() << endl; // 打印错误信息`
` }`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
6. 捕获基类异常
如果不能捕获正确的异常类型,此时也可以使用基类异常类型进行捕获。
#include <iostream>`
`#include <stdexcept> // 标准异常族`
`using namespace std;`
`void func(int i)`
`{`
` if(i % 2 == 0)`
` throw length_error("A");`
` else`
` throw domain_error("B");`
`}`
`int main()`
`{`
` try`
` {`
` func(2);`
` }catch(const logic_error& e)`
` {`
` cout << "捕获异常" << e.what() << endl;`
` }`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
7. 多重捕获
try-catch代码块中,catch块可以有多个,当进行异常捕获时,逐个进行对比捕获,通常会把派生类类异常放在前面,基类异常放在后面。
#include <iostream>`
`#include <stdexcept> // 标准异常族`
`using namespace std;`
`void func(int i)`
`{`
` if(i % 2 == 0)`
` throw length_error("A");`
` else`
` throw range_error("B");`
`}`
`int main()`
`{`
` try`
` {`
` func(1);`
` }catch(const length_error& e)`
` {`
` cout << "捕获异常A" << e.what() << endl;`
` }catch(const logic_error& e)`
` {`
` cout << "捕获异常B" << e.what() << endl;`
` }catch(const exception& e)`
` {`
` cout << "捕获异常C" << e.what() << endl;`
` }`
` cout << "主函数结束" << endl;`
` return 0;`
`}`
`
C++的异常处理机制不够完善,是否使用取决于具体的开发团队的要求。