九、C++之异常处理

一、异常的基本使用

1.1 异常的基本语法

try 视图执行, try{}中的内容
在可能出现异常的地方,抛出异常 throw
try下面的catch捕获异常
catch(捕获类型) ... 代表所有类型
如果不想抛出异常,继续向上抛出 throw
如果没有任何处理异常的地方,那么成员调用 terminate函数,中断
自定义异常类可以抛出自定义的对象(一般匿名对象)

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class MyException
{
public:
    void printError()
    {
        cout << "自定义异常类" << endl;
    }
};


int myDivede(int a, int b)
{
    if (b == 0)
    {
        // return -1;
        //throw -1;  // 抛出 int类型的异常
        // throw 3.14;  // 抛出double类型的异常, 异常必须处理,如果不处理就会报错
        throw MyException();  // 匿名对象
    }
    return a / b;
}

void test()
{
    int a = 10;
    int b = 0;
    try
    {
        myDivede(a, b);
    }
    catch (int)  // 捕获 int类型的错误
    {
        cout << "int类型异常捕获" << endl;
    }
    catch (double)
    {
        throw 'a';
        cout << "double类型异常捕获" << endl;
        // 如果不想处理这个异常,可以继续向上抛出
        
    }
    catch (MyException e)
    {
        e.printError();
    }
    catch (...)
    {
        cout << "其他类型异常捕获" << endl;
    } 

}


int main()
{
    try
    {
        test(); 
    }
    catch (double)
    {
        cout << "main 函数中double类型异常捕获" << endl;
    }
    catch (...)
    {
        cout << "main函数中其他类型异常捕获" << endl;
    }
    
    return EXIT_SUCCESS;
}

 

1.2 栈解旋

/*
    从 try开始,到throw抛出异常之前, 所有栈上的对象,都会被释放,这个过程被称为 栈解旋, 栈上构造和析构的顺序相反
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class MyException
{
public:
    void printError()
    {
        cout << "自定义异常类" << endl;
    }
};

class Person
{
public:
    Person()
    {
        cout << "Person的构造" << endl;
    }
    ~Person()
    {
        cout << "Person的析构" << endl;
    }
};

int myDivede(int a, int b)
{
    if (b == 0)
    {
        // 栈解旋 从 try开始,到throw抛出异常之前, 所有栈上的对象,都会被释放,这个过程被称为 栈解旋, 构造和析构的顺序相反
        Person p1;
        Person p2;
        throw MyException();
    }
    return a / b;
}




void test()
{
    int a = 10;
    int b = 0;
    try
    {
        myDivede(a, b);
    }
    catch (MyException e)
    {
        e.printError();
        /*
            Person的构造
            Person的构造
            Person的析构
            Person的析构
            自定义异常类
        */
    }
}


int main()
{
    test();
    return EXIT_SUCCESS;
}

1.3 异常的接口声明

/*
    void func() throw(int, cahar)  只能抛出int,char类型的异常
    此功能只能在 Qt或者linux下运行, 在visual studio下运行没有效果
*/

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

void func() throw(int)  // 代表只能抛出int类型的异常, throw()代表不抛出任何类型的异常
{
    throw -1;
}

int main()
{
    try
    {
        func();
    }
    catch (int)
    {
        cout << "int类型的异常" << endl;
    }
    
    return EXIT_SUCCESS;
}

 

1.4 异常的生命周期

/*
    MyException e  这一步会调用调用拷贝构造, 会多开销一份数据
    MyException *e 需要new出来, 如果是不是new MyException()出来的, 是通过 &MyException(),就会提前释放对象, new出来以后需要自己 delete
    MyException &e 推荐使用, 而且就产生一份数据
*/

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;


class MyException
{
public:
    MyException()
    {
        cout << "Preson的默认构造" << endl;
    }
    MyException(const MyException &p)
    {
        cout << "Person的拷贝构造" << endl;
    }
    ~MyException()
    {
        cout << "Person的析构" << endl;
    }
};

void doWork()
{
    throw MyException();
}

void test()
{
    try
    {
        doWork();
    }
    catch (MyException e) // 这一步会调用调用拷贝构造, 会多开销一份数据
    {
        cout << "异常捕获" << endl;
    }
}

void test02()
{
    try
    {
        doWork();
    }
    catch (MyException &e) // 采用引用的方式, 让异常跑出来的对象在此接收
    {
        cout << "异常捕获" << endl;
    }
}


void doWork02()
{
    throw new MyException(); // 抛出指针
}

void test03()
{
    try
    {
        doWork02();
    }
    catch (MyException *e)
    {
        cout << "异常捕获" << endl;
        delete e; // 需要自己释放对象
    }
}




int main()
{
    test();
    /*
        Preson的默认构造
        Person的拷贝构造
        异常捕获
        Person的析构
        Person的析构
    */

    test02();  // 推荐使用方式
    /*
        Preson的默认构造
        异常捕获
        Person的析构
    */

    test03();
    /*
        Preson的默认构造
        异常捕获
        Person的析构
    */


    return EXIT_SUCCESS;
}

 

1.5 异常的多态使用

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;


// 异常基类
class BaseException
{
public:
    virtual void printError()
    {

    }
};

class NullPonitException : public BaseException
{
public:
    virtual void printError()
    {
        cout << "空指针异常" << endl;
    }
};

class OutoRangeException : public BaseException
{
public:
    virtual void printError()
    {
        cout << "越界异常" << endl;
    }
};

void doWork()
{
    throw NullPonitException();
}

void test()
{
    try
    {
        doWork();
    }
    catch (BaseException & e)
    {
        e.printError();
    }
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

二、C++标准异常库

2.1 使用系统提供的标准异常

/*
    #include<stdexcept>
    throw out_of_range("年龄越界");
    catch (out_of_range &e)
    e.what() 
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;
// 使用系统提报标准异常
#include<stdexcept>

class Person
{
public:
    Person(string name, int age)
    {
        this->Name = name;
        if (age < 0 || age > 200)
        {
            // 抛出越界异常
            throw out_of_range("年龄越界");

        }
    }
    string Name;
    int Age;
};

void test()
{
    try
    {
        Person p1("wangyong", 520);
    }
    catch (out_of_range &e)
    {
        cout << e.what() << endl; // 年龄越界
    }
    
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

2.2 编写继承系统的异常类

/*
    自己的遗产类需要继承于 exception
    重写 虚析构 what()
    内部维护错误信息字符串
    构造时候传入错误信息字符串, what返回
    
    string转char * :  c_str()
*/

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class MyOutOfRangeException : public exception  // exception 系统提供的异常类
{
public:
    MyOutOfRangeException(string errorInfo)
    {
        this->Error = errorInfo;
    }
    virtual ~MyOutOfRangeException()
    {

    }
    virtual const char * what()
    {
        // string转char *
        return this->Error.c_str();  
    }
    string Error;
};

class Person
{
public:
    Person(string name, int age)
    {
        this->Name = name;
        if (age < 0 || age > 200)
        {
            throw MyOutOfRangeException("年龄越界");
        }
    }
    string Name;
    int Age;
};

void test()
{
    try
    {
        Person p1("wangyong", 520);
    }
    catch (MyOutOfRangeException &e)
    {
        cout << e.what() << endl; // 年龄越界
    }
}


int main()
{
    test();
    return EXIT_SUCCESS;
}

 

posted on 2022-03-20 15:46  软饭攻城狮  阅读(32)  评论(0编辑  收藏  举报

导航