• C++中的异常


    一,异常的推演

    1.函数与异常

      平时我们在函数中出现异常情况时通常通过return终止函数并返回一个值,然后在函数上层来获取值并判断是什么异常情况。因为函数是栈结构的,所以return的时候是通过栈结构逐步往上的,不能够跨函数直接抛出,不方便。所以C++推出了异常机制,通过异常机制我们可以轻松的捕获要出现的异常。

    2.C++中异常的基本演示

    # include<iostream>
    using namespace std;
    
    /* 定义求商函数,如果除数为0,抛出double类型异常 */
    double div(double d1, double d2)
    {
        if (d2 == 0)
        {
            throw d2;
        }
        return d1 / d2;
    }
    
    int main()
    {
        /* try...catch语句来捕获异常 */
        try
        {
            double result = div(1.02, 0.0);
        }
        catch (double e)
        {
            /* C++中的异常严格要求类型匹配,即抛出什么的异常就catch什么类型的异常 */
            cout << e << "不能作除数" << endl;
        }
        catch (...)
        {
            cout << "未知异常" << endl;
        }
    
        return 0;
    }

     3.C++中异常的总结

    • 异常的捕捉严格匹配数据类型,不支持类型自动转换,throw的是int类型则catch的必须是int类型否则不会匹配。
    • 一般我们在异常最后加入catch(...)这样能够捕获任意异常。

    二,自定义异常类

    1.异常类

      按照面向对象的思维,我们的异常也应该是一个对象,所以在抛出异常的时候,我们通常自定义一个异常类,然后把异常信息放入异常类中,然后在捕捉到异常对象的时候,再调用对象的方法,打印出异常的信息。

    2.异常类代码演示

    # define _CRT_SECURE_NO_WARNINGS
    # include<iostream>
    using namespace std;
    
    /* 自定义异常类 */
    class MyException
    {
    private:
        char * content;
    public:
        /* 异常类构造函数 */
        MyException(const char * content)
        {
            this->content = new char[strlen(content) + 1];
            strcpy(this->content, content);
            cout << "异常类有参构造函数执行" << endl;
        }
        /* 异常类拷贝构造函数 */
        MyException(const MyException& me)
        {
            this->content = new char[strlen(me.content) + 1];
            strcpy(this->content, me.content);
            cout << "异常类拷贝构造函数执行" << endl;
        }
        /* 异常类析构函数 */
        ~MyException()
        {
            if (this->content != NULL)
            {
                delete[] this->content;
                this->content = NULL;
            }
            cout << "异常类的析构函数执行" << endl;
        }
        /* 异常类抛出异常信息 */
        void toString()
        {
            cout << this->content << endl;
        }
    };
    
    /* 定义测试异常的函数 */
    double divide(double d1, double d2)
    {
        if (d2 == 0)
        {
            throw MyException("除数不能为0");
            //throw new MyException("除数不能为0");
        }
        return d1 / d2;
    }
    
    int main()
    {
        try
        {
            double result = divide(1, 0);
            cout << "result = " << result << endl;
        }
        catch (MyException e)
        {
            // catch的异常是元素类型,执行的是拷贝构造函数,存在两个异常对象,释放两个异常对象,不合理
            e.toString();
        }
        catch (MyException * e)
        {
            // catch的异常是指针类型,必须我们手动调用delete方法才能调用析构函数,不合理
            e->toString();
            delete e;
        }
        catch (MyException& e)
        {
            // catch的是引用类型,是原先抛出的对象,会自动执行析构函数,我们使用引用来接收抛出的异常对象
            e.toString();
        }
        catch (...)
        {
            cout << "未知异常" << endl;
        }
    
        return 0;
    }

    3.自定义异常类总结

    • 抛出异常对象通常用引用的方式来catch这个对象,如果是元素catch异常对象则会执行拷贝构造函数,创建两个重复异常对象并释放两次对象,所以说不合理。如果catch的是指针类型,不会自动调用该对象的析构函数必须我们手动delete,也不符合自动调用的逻辑,所以使用引用的方式来catch异常对象。

    三,标准异常类

    1.标准异常类

      C++中提供了标准的异常类,需要# include<exception>,标准异常类为exception,该类有个what函数,可以打印异常对象的异常信息。该what函数是虚函数,我们需要继承exception类并重写该what函数,在捕捉异常的时候,我们用父类的引用来接收自定义的标准异常类的子类对象(类型兼容性原则),然后打印该异常信息即可。

    2.标准异常类演示

    # include<iostream>
    # include<exception>
    using namespace std;
    
    /* 继承自标准异常类 */
    class DivException :public exception
    {
    private:
        const char * ptr;
    public:
        /* 构造函数接收异常信息 */
        DivException(const char * ptr)
        {
            this->ptr = ptr;
        }
        /* 重写what函数 */ 
        virtual char const * what() const
        {
            cout << this->ptr << endl;
            return ptr;
        }
    };
    /* 测试异常函数 */
    int divi(int a, int b)
    {
        if (b == 0)
        {
            throw DivException("除数不能为0");
        }
        return a / b;
    }
    
    int main()
    {
        try
        {
            divi(10, 0);
        }
        catch (exception& e)
        {
            /* 使用exception引用接收自定义的子类对象 */
            e.what();
        }
        catch (...)
        {
            cout << "未知异常" << endl;
        }
    
        return 0;
    }
  • 相关阅读:
    PCB genesis方槽加内角槽孔实现方法
    PCB genesis连孔加除毛刺孔(槽孔与槽孔)实现方法(三)
    PCB genesis连孔加除毛刺孔(圆孔与槽孔)实现方法(二)
    PCB genesis连孔加除毛刺孔(圆孔与圆孔)实现方法(一)
    为什么要用Redis而不直接用Map做缓存
    Linux 查询端口被占用命令
    HashMap 和 Hashtable 的区别
    RandomAccess是什么
    接口和抽象类的区别是什么?
    为什么 Java 中只有值传递?
  • 原文地址:https://www.cnblogs.com/metalsteel/p/6287079.html
Copyright © 2020-2023  润新知