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;
}
相关推荐
只待花开26 分钟前
QT5.12.9 通过MinGW64 / MinGW32 cmake编译Opencv4.5.1
开发语言·qt
代码小狗Codog28 分钟前
C++ Qt 自制开源科学计算器
c++·qt
我写代码菜如坤30 分钟前
C#中Stopwatch的使用
开发语言·c#
wjs20241 小时前
SQLite Glob 子句
开发语言
MarkHD4 小时前
javascript 常见设计模式
开发语言·javascript·设计模式
海盗猫鸥5 小时前
C++入门基础篇(1)
开发语言·c++·学习
专注成就自我5 小时前
java使用easypoi模版导出word详细步骤
java·开发语言·word
多多*5 小时前
SpringBoot 启动流程六
java·开发语言·spring boot·后端·spring
让你三行代码QAQ6 小时前
SpringSecurity初始化过程
java·开发语言
Mr_Richard6 小时前
Java动态代理的实现方式
java·开发语言