zoukankan      html  css  js  c++  java
  • 异常处理

    ----------------siwuxie095

       

       

       

       

       

       

       

    一般的语法知识都是在正常状态下使用的,而 异常处理

    则是在非正常状态下使用的

       

       

       

       

       

    异常处理

       

       

    有人可能会问,在 C++ 中什么是异常,又如何进行处理?

       

    所谓 异常,就是程序在运行过程当中所出现的错误

       

       

       

       

    显然,错误并不是我们所希望看到的,但是在某些情况下,

    这种错误却会出现,出现后就必须要处理

       

    不处理,就会出现程序崩溃的情况,而崩溃这种情况更是

    我们不愿意看到的

       

       

       

    对程序进行异常处理,其实就是对可以预见的错误进行

    合理的安排

       

       

       

    如果做出的安排合理,并能够给出人性化的提示,使用者

    就不会觉得突兀

       

       

       

    使用者就会根据提示做相应的操作,如:网线没插好,

    内存不足,这样使用者就会非常容易的接受你给他

    的提示,并根据提示使得程序能顺利的继续向下运行

       

       

       

       

       

    如果有些异常没有预料到,那么就会直接抛给系统

       

       

       

    系统是很粗暴的,它会将程序直接杀死,对于用户来说,

    所看到的现象就是程序直接崩溃掉,而崩溃是我们最不

    愿意看到的

       

       

       

    程序频繁地崩溃,对于开发者来说,简直就是一场噩梦

       

       

       

       

    如何来进行异常处理呢?

       

    需要用到关键字:try … catch … throw

       

       

       

    try 即 尝试运行正常的逻辑,如果在运行正常逻辑时,

    出现异常,就会通过 catch 将其捕获,捕获之后,再

    去对出现的异常进行处理

       

    throw 即 抛出,具体到这里,即 抛出异常,抛出之后,

    catch 捕获,捕获之后,再进行处理

       

       

       

    主逻辑放在 try 中,而将异常处理逻辑放在 catch 中,

    看上去非常整齐,对于阅读程序的人来说,也会非常理解你

    的程序了

       

       

       

       

    异常处理在 C++ 中的工作方式:

       

       

       

    定义 3 个函数:f1()、f2()、f3(),并用 f2() 来调用 f1(),

    用 f3() 来调用 f2()

       

    如果 f1() 在运行过程中出现了异常,那么它就会把异常向上抛,

    抛给它的调用者 f2(),如果 f2() 可以处理,则处理完成,如果

    处理不了,就继续向上抛,抛给它的更上层

       

    因为 f3() 调用了 f2(),所以,作为更上层的 f3() 就会捕获到异

    常,捕获之后就会进行相应的处理,如果处理不了,就继续向

    上抛,直到有函数可以处理

       

    如果所有的函数都不能处理,就会抛到操作系统,操作系统就会

    进行粗暴地干预了

       

       

       

    看如下实例:

       

    定义函数 fun1():

       

       

       

    函数体中写出了 throw 1;,这里只是简单的抛出了一个数字 1

    实际的程序当然不能这么写,肯定要写很多正常的逻辑,当运行

    到一个我们并不愿意看到的逻辑分支时,才通过 throw 抛出异常

       

       

       

    main() 函数中:

       

       

       

    通过 try … catch … 块来进行异常的捕获:

       

    将 fun1() 的函数调用放在 try 块中,如果它能正常的运行完成,

    那么就会执行 catch 块下面的代码,而 catch 块得不到执行

       

    如果 fun1() 不能正常的完成自己的主逻辑,而在运行的过程中

    不幸出现问题,抛出了 1,就必须要用 catch 来捕获它,捕获

    之后,就可以在 catch 块中进行相应的处理

       

    在 try 块中,如果运行到 fun1() 出现了异常,那么 fun1() 后面

    的代码将不会得到运行

       

    另外,注意:在 fun1() 中所抛出的是数字 1,它是 int 类型的,

    catch 后的括号中写上 int 才能捕获,如果抛出的是 0.1,就

    应该用 double 来进行捕获

       

       

       

    对于 try … catch … 来说,它可以不是 一对一 的,可以是 一对多

       

       

       

    对于一个 try 来说,里面有相应的主逻辑,主逻辑在运行过程中,

    可能在第一行代码抛出异常,也可能在第三行代码抛出异常

       

    抛出的异常可能是 int 类型的,也可能是 double 类型的,还有

    可能是其它类型的

       

    这时,就要根据不同的异常来做相应的处理,这种处理就非常的

    细致了

       

    如:接到 int 类型的异常,就要针对这种情况做相应的处理,告诉

    用户怎么样了,用户就会根据你的提示帮助程序正常的往下运行

       

    如果以上的所有的 catch 块,如:catch(int){}catch(double){}

    都不能捕获到相应异常,最后的 catch 块可以为大家兜底,注意写

    法:catch(…){}

       

    这种写法就是说:我可以捕获所有的异常,尽管来吧,所有的异常

    我通通可以处理

       

    但是,这种处理很野蛮,因为我们不分青红皂白,没有细致划分,

    全部一刀切的在 catch(…){} 中写相应的处理代码,无非就是告诉

    用户:你出错了,只能关闭

       

    所以,不建议直接写一个 try 后马上跟一个 catch 加三个点,而是

    在前面所有情况都处理不了,已经万般无奈了,才使用 catch(…){}

    捕获异常,进行最后的挣扎

       

       

       

    在上面的例子中有一个特点:所抛出的异常虽然是一个值,但捕获时,

    只是一种数据类型,如果想要捕获这个值该怎么办呢?

       

    看如下实例:

       

       

       

    定义函数 getChar(),传入参数分别是字符串和下标,想要从字符串

    中拿到对应下标的字符,但无法保证传入进来的下标比字符串长度短

       

    如果下标比字符串的长度还长,就要通过 throw 将异常抛出,告诉

    用户当前传入的下标是非法的

       

       

       

    采用下面的方式拿到 throw 出来的字符:

       

       

       

    catch 中,写的是 string& aval,即 取引用,此时如果传入字符串

    hello world 和 下标 100,定然会抛出异常:invalid index!

       

    这时就能通过 catch 拿到相应的值,并打印出来,清晰的告诉用户你

    的下标传错了

       

    注意:如果在 ch=getChar(str,100); 这一行代码就抛出了异常,那么

    下一行代码 cout<<ch<<endl; 就得不到运行

       

       

       

    C++ 中常见的异常:

       

       

       

       

       

       

       

    异常处理与多态的关系

       

       

    多态和异常处理有着非常紧密的联系,如下:

       

       

    定义一个异常类:Exception,假设把它定义为一个接口类,在其中

    定义一些打印的方法 异常处理的方法

       

    然后通过细分的子类来继承接口类 Exception,当抛出子类对象时,

    就都可以用这个父类去捕获了

       

       

    看如下实例:

       

       

    在 fun1() 中进行逻辑处理的过程中,不幸抛出了异常 SizeErr,

    同理,在 fun2() 中进行逻辑处理时也抛出了异常 MemoryErr

       

       

       

    二者都是 Exception 的子类,此时捕获异常的方法:

       

       

       

    不论是 fun1() 还是 fun2(),都可以通过 try … catch … 块来捕获

    异常,其中,关键是 catch 块中使用了父类 Exception,这时就可

    以捕获到 fun1() 和 fun2() 中所抛出的子类对象,并通过子类对象

    去调用相应的虚函数

       

       

       

       

    程序:

       

    Exception.h:

       

    #ifndef EXCEPTION_H

    #define EXCEPTION_H

       

    #include <iostream>

    using namespace std;

       

    //接口类 Exception

    class Exception

    {

    public:

    virtual void printException()=0;

       

    //其实,纯虚析构函数因为比较特殊,在接口类中,

    //也可以写为 virtual ~Exception(){}

    //这样就不用在 Exception.cpp 中单独为它实现了

    virtual ~Exception() = 0;

    };

       

    #endif

       

       

       

    Exception.cpp:

       

    #include "Exception.h"

       

       

    //因为将Exception类改为了接口类,

    //printException() 就不需要实现了

    //

    //void Exception::printException()

    //{

    // cout << "Exception--printException" << endl;

    //}

       

    //注意:

    //接口类的纯虚析构函数比较特别,需要进行实现,即有函数体

    //(接口类中普通的纯虚函数是没有函数体,不需要实现的)

    Exception::~Exception()

    {

       

    }

       

       

       

    IndexException.h:

       

    #ifndef INDEX_EXCEPTION_H

    #define INDEX_EXCEPTION_H

    #include "Exception.h"

       

    class IndexException :public Exception

    {

    public:

    virtual void printException();

    virtual ~IndexException(){}

    };

       

    #endif

       

       

       

    IndexException.cpp:

       

    #include "IndexException.h"

       

    void IndexException::printException()

    {

    cout << "提示:下标越界!" << endl;

    }

       

       

       

    main.cpp:

       

    #include <stdlib.h>

    #include "IndexException.h"

       

    void test1();

    void test2();

    void test3();

    void test4();

       

    //抛出的异常只有被捕获到才能进行合理的处理

    //或者说你有能力对其进行处理

    //

    //如果抛出的异常捕获不到,等待计算机替你处理,

    //系统就会非常粗暴,你的程序就会崩溃掉

    int main(void)

    {

    try

    {

    test1(); //换为 2 3 4

    }

    //虽然不能实例化接口类的对象,但可以使用

    //接口类的对象引用和对象指针

    catch (Exception &e)

    {

    e.printException();

    }

    catch (int)

    {

    cout << "exception--int" << endl;

    }

    catch (double &e)

    {

    cout << "exception--double:" << e << endl;

    }

    catch (...)//兜底用 catch(...){}

    {

    cout << "exception" << endl;

    }

    system("pause");

    return 0;

    }

       

    void test1()

    {

    throw IndexException();

    }

       

    void test2()

    {

    throw 10;

    }

       

    void test3()

    {

    throw 0.1;

    }

       

    void test4()

    {

    char ch = '#';

    throw ch;

    }

       

       

       

       

       

       

       

       

       

       

    【made by siwuxie095】

  • 相关阅读:
    存储器的分配与回收算法实现
    jsoup抓取借书记录
    java学习碰到死胡同了
    PHP MYSQL登陆和模糊查询
    JAVA进阶之路(一)
    String是最基本的数据类型吗?
    面向对象的特征有哪些方面
    sqoop
    你真的理解 new 了吗?
    面试题目 字符串的去重与压缩(统计)
  • 原文地址:https://www.cnblogs.com/siwuxie095/p/6813146.html
Copyright © 2011-2022 走看看