首页 > 代码库 > C++中的异常

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;}

 

C++中的异常