C++---异常

在这里插入图片描述


一.异常的介绍

当我们编写比较复杂的,个人难以管理的系统时,异常和命名空间最为有用。
异常在工作中经常使用,异常就是在程序运行中发生的难以预料的、不正常的事件而导致偏离正常流程的现象。发生异常将导致正常流程不能进行,就需要对异常进行处理。
异常使得我们能将问题的检测与解决过程分离开来。程序的一部分负责检测问题的出现,然后解决该问题的任务传递给程序的另一部分。检测环节无须知道问题处理模块的细节。
如下,对于除0的处理

#include <iostream>
using namespace std;

double fun(double a, double b)//除法函数
{
    if (b == 0)//除数为0,抛出异常
    {
        throw b;
    } 
    return a / b; //否则返回两个数的商
}
int main()
{
    double res;
    try //可能出现异常
        {
            res = fun(4, 5);
            cout << 4 << "/" << 5 << " = " << res << endl;
            res = fun(6, 0);//出现异常,函数内部会抛出异常
            cout << 6 << "/" << 0 << " = " << res << endl;//这一句没有执行
        }
    catch (double a) //捕获并处理异常
        {
            cout << "a=" << a << endl;
            cerr << "出现除0错误,程序中止了,请检查!\n";
            exit(1); //异常退出程序
        }
    return 0;
}

在这里插入图片描述

异常的抛出和处理主要使用了:throw语句和try-catch语句。


throw语句

如果检测到异常,则抛出异常。
格式为:

throw 表达式;

表达式的类型作为异常事件的类型,表达式的类型和值将传给捕获该异常的程序。表达式可以是一个基本类型,也可以是一个对象。这个表达式的类型可以和函数的返回值类型不同。
当执行一个throw时,跟在thorw后面的语句将不再被执行。程序的控制权从throw转移到与之匹配的catch模块。

try-catch语句

捕获处理异常的语句是try-catch语句。
该语句格式如下:

try{ 可能引发异常的语句序列 }           //受保护代码
catch(异常类型1 异常变量1){ 处理代码1}  //异常处理1
catch(异常类型2 异常变量2){ 处理代码2} //异常处理2
...
catch(异常类型n 异常变量n){ 处理代码n} //异常处理n
catch(...) { 处理代码n+1}            //异常处理n+1

其中,关键字try包括的语句称为try子句。这个语句块中的代码被称为受保护代码,可以包含多条语句。受保护代码描述正常的执行流程,但这些语句的执行可能引发异常。如果没有发生异常,try-catch 语句就正常结束,所有的catch都不执行。如果引发了某种类型的异常,就按 catch 子句顺序逐个匹配异常类型,捕获并处理该异常。
**异常是按其类型进行捕获的。**一个catch子句捕获一类异常。异常类型及变量指明要捕获的异常的类型,及接收异常的值。例如,catch(double a),要捕获的异常类型为double,如果真的捕获到该类异常,那么变量a就有这个异常的值,这个值就是前面用throw语句抛出的。
有一种特殊的catch子句,就是catch(…),它的含义是捕获所有异常。在多个 catch 子句中,它应放在最后。

异常处理步骤

在执行try子句中的受保护代码时,如果引发一个异常,系统就到catch子句中寻找处理该异常类型的入口。这个寻找过程称为异常类型匹配,它按如下步骤进行。

(1)由throw语句引发异常事件之后,系统依次检查catch子句以寻找相匹配的处理异常事件入口。如果某个 catch 子句的异常类型与异常事件类型相一致,该异常就被捕获,然后执行该子句的异常处理代码。如果有多个 catch 子句的异常类型相匹配,只执行最前面第一个匹配的异常处理代码。

(2)若没有找到任何相匹配的 catch 子句,该异常就被传递到外层作用域。如果外层作用域是函数,就传递到函数的调用方。

一个异常的生命期从被throw抛出来,然后被某个catch子句捕获,其生命期就结束了。一个异常从抛出来到被捕获,可能穿越多层作用域或函数调用。如果到main函数都未被捕获,将导致程序终止。

例如下面的程序

#include <iostream>
#include <string>
using namespace std;

class DivdeByZeroException //定义除0异常类
{
string message; //记录异常信息
public:
DivdeByZeroException() :message("除0错误!\n") {}
const string& what() { return message; }
};

double fun(int a, int b) //除法函数
{
    if (b == 0) //抛出异常
    {
        throw DivdeByZeroException{}; //异常类型为DivdeByZeroException
    }
    return(double)a / b; //返回两个数的商
}
int main()
{
    int n1, n2;
    double res;
    cout << "请输入两个整数 : ";
    while (cin >> n1 >> n2)
        {
            try //受保护代码
                {
                    res = fun(n1, n2);
                    cout << n1 << "/" << n2 << " = " << res << endl;
                }
            catch (DivdeByZeroException ex) //捕获并处理异常
                {
                    cout << ex.what();
                }
            cout << "请输入两个整数 : ";
        }
    return 0;
}

未捕获异常的处理

如果一个异常没有被catch捕获,这种情况就叫未捕获异常。如果一个异常没有被捕获,则系统将自动调用abort()函数来终止程序执行。


class A {};
class B {};

void f()
{
    int err = 1;
    if (err)
    {
        cout << " 抛出异常 B" << endl;
        throw B(); //抛出异常,类型为B
    }
}
int main()
{
    try //保护代码
        {
            f();//函数内部抛出异常
        }
    catch (A) //捕获A类型异常
        {
            cout << " 捕获异常类型 A" << endl;;
            exit(1); 
        }
    cout << " 再见" << endl;;
    return 0;
}

上述代码,抛出的是B类异常,但捕获的是A类异常,导致异常没有被捕获。程序运行结果如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小小苏

感谢大佬支持!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值