C++异常

目录

1、异常的概念:

2、异常的处理方法:

2、异常的语法:

3、栈解旋:

4、异常接口说明:

5、异常变量的声明周期:

6、异常的多态:

7、C++标准异常库:

8、编写自己的异常类:


1、异常的概念:

异常处理就是处理程序中的错误

异常事件:数组下标越界、空指针、内存不足、读写文件等等。

C语言有错误----段错误-------停止运行

C++有异常------抛出------捕获-------解决(异常的抛出和解决是分离的)

2、异常的处理方法:

C语言:

1、使用整形变量作为返回值作为错误的标记;

2、使用errno宏(可以理解为全局的整形变量去记录错误),最后抛出一条语句的问题。

#include 
#include 
#include 

int main() {
    std::ifstream file("nonexistent.txt");

    if (!file.is_open()) {
        std::cout << "Failed to open file." << std::endl;
        std::cout << "Error code: " << errno << std::endl;
    }

    return 0;
}

C++异常:

本质是一个类,有名称,抛出异常-----捕获异常。

2、异常的语法:

void test01()
{
    //尝试捕获异常
    try
    {
        throw 'a';
    }
    catch(int)
    {
        cout << "捕获int异常" << endl;
    }
    catch(char)
    {
        cout << "捕获char异常" << endl;
    }
    catch(...)
    {
        cout << "捕获其他异常" << endl;
    }
}

在异常处理中有严格的类型匹配机制。

3、栈解旋:

问题抛出:try中的对象如何处理

C++异常_第1张图片

异常抛出后从进入try起,到异常被抛出前,这期间在栈上构造的所有对象,都会被自动析构,析构和构造的顺序相反。这一过程称为栈解旋。

class Data
{
public:
    int a;
public:
    Data(){}
    Data(int a)
    {
        this->a = a;
        cout << "Data构造 a = " << this->a << endl;
    }
    ~Data()
    {
        cout << "Data析构 a = " << a << endl;
    }
};
void test02()
{
    try{
        Data ob1(10);
        Data ob2(20);
        throw 30;
    }
    catch(int n){
        cout << "捕获int异常 n = " << n << endl;
    }
}

C++异常_第2张图片

4、异常接口说明:

lass DivideByZeroException : public std::exception
{
public:
    const char* what() const noexcept override
    {
        return "Divide by zero!";
    }
};

class OverflowException : public std::exception
{
public:
    const char* what() const noexcept override
    {
        return "Result overflows!";
    }
};

int divide(int a, int b)
{
    if (b == 0)
    {
        throw DivideByZeroException();
    }
  
    if (a == INT_MIN && b == -1)
    {
        throw OverflowException();
    }

    return a / b;
}

int main()
{
    try
    {
        int result = divide(5, 2);
        std::cout << "Result: " << result << std::endl;
    }
    catch (DivideByZeroException& e)
    {
        std::cout << "Caught an exception: " << e.what() << std::endl;
    }
    catch (OverflowException& e)
    {
        std::cout << "Caught an exception: " << e.what() << std::endl;
    }
    catch (std::exception& e)
    {    //捕获其他异常
        std::cout << "Caught an exception: " << e.what() << std::endl;
    }

    return 0;
}

上诉代码自定义了俩个类,分别用来判断除数为0或者超出范围,自定义一个函数divide传递俩个参数并且判断条件作为抛出异常。主函数中try并且调用函数,最后捕捉异常

5、异常变量的声明周期:

异常接收:最佳采用引用来接收。

{
public:
    int a;
public:
    Data(){}
    Data(int a)
    {
        this->a = a;
        cout << "Data构造 a = " << this->a << endl;
    }
    Data(const Data &ob)
    {
        cout << "Data拷贝构造 " << endl;
    }
    ~Data()
    {
        cout << "Data析构 a = " << a << endl;
    }
};
void test03()
{
    try
    {
        Data ob(10);
        throw ob;
    }
    catch(Data &ob)   ///< 用引用接收(普通变量、指针变量)
    {
        cout << ob.a << endl;
    }
}

普通变量捕获异常:形参占用空间,拷贝构造也会耗时。

指针变量捕获异常:指针边量也会占用空间,必须调用delete。

引用变量捕获异常:不占用空间,建议使用引用来接收异常。

6、异常的多态:

class Base
{
public:
//基类定义虚函数,方便子类多态处理错误(不用纯虚函数的原因要实例化对象)
    virtual void printError(){}
};
class nullPointerException:public Base
{
public:
//重写虚函数,动态多态
    virtual void printError()
    {
        cout << "出现空指针异常" << endl;
    }
};
class outofrangeException:public Base
{
public:
    virtual void printError()
    {
        cout << "出现越界异常" << endl;
    }
};
void test04()
{
    try
    {
        //throw nullPointerException();  ///<匿名对象
        throw outofrangeException();
    }
    catch(Base &ex)
    {
         ex.printError();
    }
}

7、C++标准异常库:

C++异常_第3张图片

8、编写自己的异常类:

1、必须继承exception。

2、必须重写what()函数。

#include 、
using namespace std;
//自定义的异常类继承库中的异常类exception
class MyoutofRange:public exception
{
private:
    char *str;
public:
    MyoutofRange(){}
    MyoutofRange(char *s)
    {
        str = s;
    }
    //重写what函数(what在库中是纯虚函数),无论继承虚函数还是纯虚函数virtual可加可不加,系统默认有
    virtual const char *what() const throw()
    {
        return str;
    }
};
void test01()
{
    try
    {
        throw MyoutofRange("我越界了");
    }//exception本来是不能实例化对象,但是派生类重写了村虚函数,所以可以实例化
    //exception &ex会加上自身的异常库但是MyoutofRang只会有自己重写的异常库和子类的异常库。
    catch(exception &ex)
    {
        cout<

你可能感兴趣的:(C++,c++,开发语言)