C++ DAY08 异常

概念

异常事件(如:除 0 溢出,数组下标越界,所要读取的文件不存在 , 空指针,内存不足
等等)
在 C 语言对错误的处理是两种方法:
一是使用整型的返回值标识错误;
二是使用 errno 宏(可以简单的理解为一个全局整型变量)去记录错误。
C++ 异常不可忽略 ( 如果忽略,进程结束 ) 。
异常作为一个类,可以拥有自己的成员,这些成员就可以传递足够的信息。
抛出异常 ----> 捕获异常。
示例:

cpp 复制代码
int main(int argc, char *argv[])
{
    int num = 10 / 0;
    cout << "OVER" << endl;
    return 0;
}
//不会显示OVER,程序异常结束

抛出异常

语法:throw 值或变量;

例如:
throw 0;
throw 1.1;
throw 'a';
throw "abc";

捕获异常

语法:
try{
可能会产生异常的代码
111
222 出现异常
333
}
catch( 数据类型 1 变量名 )
{
当throw 的值与数据类型 1 相同进入此处
}
catch( 数据类型 2 变量名 )
{
当throw 的值与数据类型 2 相同进入此处
}
...
catch(...)
{
当throw 的值以上数据类型都不相同进入此处
}

示例

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
//异常步骤,抛出异常,捕获异常
int mydiv(int a,int b)
{
    if(b == 0)
    {
        // 抛出异常
        int num = 0;
        throw num;
    }
    return a / b;
}
void test01(){
    try{
        mydiv(10,0);
    }
    catch(int e)
    {
        cout << e << endl;
    }
        catch(char const* s)
    {
        cout << s << endl;
    }
        catch(...)
    {
        cout << "其他异常" << endl;
    }
}
int main(int argc, char *argv[])
{
    test01();
    return 0;
}

栈解旋

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

示例

cpp 复制代码
class A{
private:
int num;
public:
A(int num):num(num)
{
    cout << "构造函数" << num << endl;
}
~A()
{
    cout << "析构函数" << num << endl;
}
};
void test02()
{
    A a1(1);
    A a2(2);
    throw 0;
}
int main(int argc, char *argv[])
{
    try{
        test02();
    }
    catch(...)
    {
    }
    return 0;
}

结果
构造函数1
构造函数2
析构函数2
析构函数1

异常的接口声明

作用
限定异常抛出的类型种类

语法
返回值类型 函数名( 形参列表 )throw( 数据类型 1, 数据类型 2,...)
{
函数体
}
注意:
声明异常后,当前函数中只能抛出指定类型的异常
throw():不允许抛出任何异常

示例

cpp 复制代码
void fun01()throw(int,char)
{
    // throw 10;//可以
    // throw 'a';//可以
    // throw 3.14f;//不可以
}
void test03(){
    try{
        fun01();
    }
    catch(int)
    {
        cout << "int的异常" << endl;
    }
    catch(char)
    {
        cout << "char的异常" << endl;
    }
    catch(float)
    {
        cout << "float的异常" << endl;
    }
}
int main(int argc, char *argv[])
{
    test03();
    return 0;
}

异常对象的生命周期

示例1:抛出异常对象

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
class B{
private:
    int num;
public:
    B(int num):num(num)
    {
        cout << "构造函数" << num << endl;
    }
    B(const B& b)
    {
        this->num = b.num;
        cout << "拷贝构造" << num << endl;
    }
    ~B()
    {
        cout << "析构函数" << num << endl;
    }
};
void fun02()
{
    throw B(10);
}
void test04()
{
    try
    {
        fun02();
    }
    catch(B b)
    {
    }
}
int main(int argc, char *argv[])
{
    test04();
    cout << "OVER" << endl;
    return 0;
}

结果

示例2:抛出异常对象指针

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
class B{
private:
    int num;
public:
    B(int num):num(num)
    {
        cout << "构造函数" << num << endl;
    }
    B(const B& b)
    {
        this->num = b.num;
        cout << "拷贝构造" << num << endl;
    }
    ~B()
    {
        cout << "析构函数" << num << endl;
    }
};
void fun02()
{
    throw new B(10);
}
void test04()
{
    try{
        fun02();
    }
    catch(B *b)
    {
    }
}
int main(int argc, char *argv[])
{
    test04();
    cout << "OVER" << endl;
    return 0;
}

结果:

示例3:抛出异常对象引用

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
class B{
private:
    int num;
public:
    B(int num):num(num)
    {
        cout << "构造函数" << num << endl;
    }
    B(const B& b)
    {
        this->num = b.num;
    cout << "拷贝构造" << num << endl;
    }
    ~B()
    {
        cout << "析构函数" << num << endl;
    }
};
void fun02()
{
    throw B(10);
}
void test04()
{
    try{
        fun02();
    }
    catch(B &b)
    {
    }
}
int main(int argc, char *argv[])
{
    test04();
    cout << "OVER" << endl;
    return 0;
}

结果:

异常的多态

概念 : 子类异常对象可以被父类异常类型捕获
示例1:

cpp 复制代码
class BaseException{};
class MyException01:public BaseException{};
class MyException02:public BaseException{};
void test05()
{
    try{
        throw MyException01();
    }
    catch(BaseException)
    {
        cout << "可以捕获子类异常" << endl;
    }
}
int main(int argc, char *argv[])
{
    test05();
    return 0;
}

示例 2: 子类异常重写父类虚函数

cpp 复制代码
class BaseException{
public:
    virtual void printMsg(){}
};
class NullException:public BaseException{
public:
    virtual void printMsg(){
        cout << "空指针异常" << endl;
    }
};
class ArrOutException:public BaseException{
public:
    virtual void printMsg(){
        cout << "数组下标越界异常" << endl;
    }
};
void test05()
{
    try{
        throw NullException();
    }
    catch(BaseException &e)
    {
        e.printMsg();
    }
}
int main(int argc, char *argv[])
{
    test05();
    return 0;
}

标准异常库

简介

标准库中也提供了很多的异常类,它们是通过类继承组织起来的。异常类继承层级 . 结构图
所示

标准异常使用

cpp 复制代码
void test06()
{
    try{
        throw bad_alloc();
    }
    catch(exception &e)
    {
        cout << e.what() << endl;
    }
}
int main(int argc, char *argv[])
{
    test06();
    return 0;
}

自定义异常

步骤
1,定义一个类
2,继承与异常类
3,重写 what 方法

示例

cpp 复制代码
class my_exception:public exception
{
private:
    char* msg;
public:
    my_exception()
    {
    }
    my_exception(char* msg)
    {
        this->msg = msg;
    }
    const char *what()const noexcept
    {
        return msg;
    }
};
void test07()
{
    try{
        throw my_exception("自定义异常");
    }
    catch(exception &e){
        cout << e.what() << endl;
    }
}
int main(int argc, char *argv[])
{
    test07();
    return 0;
}
相关推荐
薯条不要番茄酱几秒前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
今天吃饺子5 分钟前
2024年SCI一区最新改进优化算法——四参数自适应生长优化器,MATLAB代码免费获取...
开发语言·算法·matlab
是阿建吖!6 分钟前
【优选算法】二分查找
c++·算法
努力进修9 分钟前
“探索Java List的无限可能:从基础到高级应用“
java·开发语言·list
Ajiang28247353042 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空2 小时前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10225 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
‘’林花谢了春红‘’7 小时前
C++ list (链表)容器
c++·链表·list
----云烟----7 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024067 小时前
SQL SELECT 语句:基础与进阶应用
开发语言