AI 助理
备案 控制台
开发者社区 开发与运维 文章 正文

C++的异常类型与多级catch匹配

简介: try-catch 的用法:try{ // 可能抛出异常的语句}catch(exceptionType variable){ // 处理异常的语句}我们还遗留下一个问题,就是 catch 关键字后边的exceptionType variable,这节就来详细分析一下。exceptionType是异常类型,它指明了当前的 catch 可以处理什么类型的异常;variable是一个变量,用来接收异常信息。当程序抛出异常时,会创建一份数据,这份数据包含了错误信息,程序员可以根据这些信息来判断到底出了什么问题,接下来怎么处理。异常既然是一份数据,那么就应该有数据类型。

try-catch 的用法:

try{
    // 可能抛出异常的语句
}catch(exceptionType variable){
    // 处理异常的语句
}

我们还遗留下一个问题,就是 catch 关键字后边的exceptionType variable,这节就来详细分析一下。exceptionType是异常类型,它指明了当前的 catch 可以处理什么类型的异常;variable是一个变量,用来接收异常信息。

当程序抛出异常时,会创建一份数据,这份数据包含了错误信息,程序员可以根据这些信息来判断到底出了什么问题,接下来怎么处理。异常既然是一份数据,那么就应该有数据类型。

C++ 规定,异常类型可以是 int、char、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型。C++ 语言本身以及标准库中的函数抛出的异常,都是 exception 类或其子类的异常。也就是说,抛出异常时,会创建一个 exception 类或其子类的对象。exceptionType variable和函数的形参非常类似,当异常发生后,会将异常数据传递给 variable 这个变量,这和函数传参的过程类似。

当然,只有跟 exceptionType 类型匹配的异常数据才会被传递给 variable,否则 catch 不会接收这份异常数据,也不会执行 catch 块中的语句。换句话说,catch 不会处理当前的异常。

我们可以将 catch 看做一个没有返回值的函数,当异常发生后 catch 会被调用,并且会接收实参(异常数据)。

但是 catch 和真正的函数调用又有区别:

  • 真正的函数调用,形参和实参的类型必须要匹配,或者可以自动转换,否则在编译阶段就报错了。
  • 而对于 catch,异常是在运行阶段产生的,它可以是任何类型,没法提前预测,所以不能在编译阶段判断类型是否正确,只能等到程序运行后,真的抛出异常了,再将异常类型和 catch 能处理的类型进行匹配,匹配成功的话就“调用”当前的 catch,否则就忽略当前的 catch。

总起来说,catch 和真正的函数调用相比,多了一个「在运行阶段将实参和形参匹配」的过程。另外需要注意的是,如果不希望 catch 处理异常数据,也可以将 variable 省略掉,也即写作:

try{
    // 可能抛出异常的语句
}catch(exceptionType){
    // 处理异常的语句
}

这样只会将异常类型和 catch 所能处理的类型进行匹配,不会传递异常数据了。

多级 catch

前面的例子中,一个 try 对应一个 catch,这只是最简单的形式。其实,一个 try 后面可以跟多个 catch:

try{
        //可能抛出异常的语句
    }catch (exception_type_1 e){
        //处理异常的语句
    }catch (exception_type_2 e){
        //处理异常的语句
    }
    //其他的catch
    catch (exception_type_n e){
        //处理异常的语句
    }

当异常发生时,程序会按照从上到下的顺序,将异常类型和 catch 所能接收的类型逐个匹配。一旦找到类型匹配的 catch 就停止检索,并将异常交给当前的 catch 处理(其他的 catch 不会被执行)。如果最终也没有找到匹配的 catch,就只能交给系统处理,终止程序的运行。下面的例子演示了多级 catch 的使用:

#include <iostream>
    #include <string>
    using namespace std;
    class Base{ };
    class Derived: public Base{ };
    int main(){
        try{
            throw Derived();  //抛出自己的异常类型,实际上是创建一个Derived类型的匿名对象
            cout<<"This statement will not be executed."<<endl;
        }catch(int){
            cout<<"Exception type: int"<<endl;
        }catch(char *){
            cout<<"Exception type: cahr *"<<endl;
        }catch(Base){  //匹配成功(向上转型)
            cout<<"Exception type: Base"<<endl;
        }catch(Derived){
            cout<<"Exception type: Derived"<<endl;
        }
        return 0;
    }

运行结果:

Exception type: Base

在 catch 中,我们只给出了异常类型,没有给出接收异常信息的变量。

本例中,我们定义了一个基类 Base,又从 Base 派生类出了 Derived。抛出异常时,我们创建了一个 Derived 类的匿名对象,也就是说,异常的类型是 Derived。我们期望的是,异常被catch(Derived)捕获,但是从输出结果可以看出,异常提前被catch(Base)捕获了,这说明 catch 在匹配异常类型时发生了向上转型(Upcasting)。

catch 在匹配过程中的类型转换

C/C++ 中存在多种多样的类型转换,以普通函数(非模板函数)为例,发生函数调用时,如果实参和形参的类型不是严格匹配,那么会将实参的类型进行适当的转换,以适应形参的类型,这些转换包括:

  • 算数转换:例如 int 转换为 float,char 转换为 int,double 转换为 int 等。
  • 向上转型:也就是派生类向基类的转换,请猛击《C++向上转型(将派生类赋值给基类)》了解详情。
  • const 转换:也即将非 const 类型转换为 const 类型,例如将 char * 转换为 const char *。
  • 数组或函数指针转换:如果函数形参不是引用类型,那么数组名会转换为数组指针,函数名也会转换为函数指针。
  • 用户自定的类型转换。

catch 在匹配异常类型的过程中,也会进行类型转换,但是这种转换受到了更多的限制,仅能进行「向上转型」、「const 转换」和「数组或函数指针转换」,其他的都不能应用于 catch。向上转型在上面的例子中已经发生了,下面的例子演示了 const 转换以及数组和指针的转换:

#include <iostream>
    using namespace std;
    int main(){
        int nums[] = {1, 2, 3};
        try{
            throw nums;
            cout<<"This statement will not be executed."<<endl;
        }catch(const int *){
            cout<<"Exception type: const int *"<<endl;
        }
        return 0;
    }

运行结果:

Exception type: const int *

nums 本来的类型是int [3],但是 catch 中没有严格匹配的类型,所以先转换为int *,再转换为const int *

数组也是一种类型,数组并不等价于指针,这点已在《数组和指针绝不等价,数组是另外一种类型》和《数组到底在什么时候会转换为指针》中进行了详细讲解。

芯动大师
目录
相关文章
可能只会写BUG
|
18天前
|
安全 程序员 C语言
C++(四)类型强转
本文详细介绍了C++中的四种类型强制转换:`static_cast`、`reinterpret_cast`、`const_cast`和`dynamic_cast`。每种转换都有其特定用途和适用场景,如`static_cast`用于相关类型间的显式转换,`reinterpret_cast`用于低层内存布局操作,`const_cast`用于添加或移除`const`限定符,而`dynamic_cast`则用于运行时的类型检查和转换。通过具体示例展示了如何正确使用这四种转换操作符,帮助开发者更好地理解和掌握C++中的类型转换机制。
可能只会写BUG
14 0
hylreg
|
24天前
|
C++
使用 QML 类型系统注册 C++ 类型
使用 QML 类型系统注册 C++ 类型
hylreg
26 0
qq2108462953
|
1月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
qq2108462953
30 0
呆呆宝
|
2月前
|
编译器 C++ 运维
开发与运维函数问题之函数的返回类型如何解决
开发与运维函数问题之函数的返回类型如何解决
呆呆宝
30 6
萝卜丝丸子
|
2月前
|
C++
C++ 异常机制问题之捕获异常的问题如何解决
C++ 异常机制问题之捕获异常的问题如何解决
萝卜丝丸子
18 2
长梦
|
2月前
|
安全 编译器 C++
C++一分钟之-模板元编程实例:类型 traits
【7月更文挑战第15天】C++的模板元编程利用编译时计算提升性能,类型traits是其中的关键,用于查询和修改类型信息。文章探讨了如何使用和避免过度复杂化、误用模板特化及依赖特定编译器的问题。示例展示了`is_same`类型trait的实现,用于检查类型相等。通过`add_pointer`和`remove_reference`等traits,可以构建更复杂的类型转换逻辑。类型traits增强了代码效率和安全性,是深入C++编程的必备工具。
长梦
49 11
长梦
|
2月前
|
C++
C++一分钟之-类型别名与using声明
【7月更文挑战第20天】在C++中,类型别名和`using`声明提升代码清晰度与管理。类型别名简化复杂类型,如`using ComplexType = std::vector&lt;std::shared_ptr&lt;int&gt;&gt;;`,需注意命名清晰与适度使用。`using`声明引入命名空间成员,避免`using namespace std;`全局污染,宜局部与具体引入,如`using math::pi;`。恰当应用增强代码质量,规避常见陷阱。
长梦
53 5
zcq5jk6y5y5e4
|
1月前
|
设计模式 安全 IDE
C++从静态类型到单例模式
C++从静态类型到单例模式
zcq5jk6y5y5e4
25 0
დ旧言~
|
2月前
|
安全 Java 程序员
【C++11】异常知多少
【C++11】异常知多少
დ旧言~
30 7
长梦
|
2月前
|
C++ 开发者
C++一分钟之-概念(concepts):C++20的类型约束
【7月更文挑战第4天】C++20引入了Concepts,提升模板编程的类型约束和可读性。概念定义了模板参数需遵循的规则。常见问题包括过度约束、约束不完整和重载决议复杂性。避免问题的关键在于适度约束、全面覆盖约束条件和理解重载决议。示例展示了如何用Concepts限制模板函数接受的类型。概念将增强模板的安全性和灵活性,但需谨慎使用以防止错误。随着C++的发展,Concepts将成为必备工具。
长梦
63 2

热门文章

最新文章

  • 1
    C++模板初阶
  • 2
    C++语言基础 例程 案例:一个接口,多种方法
  • 3
    C++编程规范之18:尽可能局部地声明变量
  • 4
    C++多进程并发框架FFLIB
  • 5
    C++ Internals: STL之Map
  • 6
    C/C++程序员上手C#应该知道的100件事(21~30)
  • 7
    C++语言基础 例程 类模板
  • 8
    C++实践参考解答:我的数组类
  • 9
    《C++语言基础》实践参考——图书馆的书
  • 10
    Eclipse C/C++开发环境搭建
  • 1
    C++ new和delete的用法
    68
  • 2
    为什么c++要引入class关键字
    54
  • 3
    【C++】使用g++指令控制【翻译】各个过程
    44
  • 4
    【C++】一文深入浅出带你参透库中的几种 [ 智能指针 ]及其背后实现原理(代码&图示)
    53
  • 5
    【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
    62
  • 6
    【C++】istream类型对象转换为逻辑条件判断值
    41
  • 7
    【C++】一文全解四种经典 [ 特殊类 ]的设计
    45
  • 8
    【C++】【C++的常变量取地址问题(对比C的不同)】const修饰的常变量&volatile修饰用法详解(代码演示)
    38
  • 9
    【C++】C++中规范[ 类型转换标准 ] 的四种形式
    45
  • 10
    【C++小小知识点】重载、覆盖(重写)、隐藏(重定义)的对比【详解】(23)
    64
  • 相关课程

    更多
  • C++ 入门教程开发文档
  • 相关电子书

    更多
  • 使用C++11开发PHP7扩展
  • GPON Class C++ SFP O;T Transce
  • GPON Class C++ SFP OLT Transce
  • 下一篇
    搭建自己的私有云盘工具总结

    玻璃钢生产厂家广东美陈玻璃钢动物雕塑费用榆树玻璃钢雕塑工程报价玻璃钢雕塑的时间黑龙江玻璃钢雕塑批发番禺玻璃钢雕塑彩绘招聘信息防城港玻璃钢座椅雕塑造价北京大型主题商场美陈厂家供应承德玻璃钢雕塑电话新郑镂空不锈钢校园玻璃钢雕塑呼市商场室外美陈公司襄阳定做玻璃钢雕塑十堰玻璃钢商场美陈绍兴商场卡通雕塑美陈玻璃钢佛像雕塑出售山东开业商场美陈供应信阳抽象玻璃钢仿铜雕塑绍兴家用玻璃钢花盆襄城玻璃钢雕塑河南标牌标识玻璃钢雕塑设计漳平玻璃钢名人雕塑大型玻璃钢花盆研究广东周年庆典商场美陈平凉广场玻璃钢雕塑定做南充玻璃钢卡通雕塑青海玻璃钢门头雕塑大型玻璃钢雕塑影视道具装饰山东公园玻璃钢雕塑图片广州玻璃钢影视人物雕塑玻璃钢仿石落地雕塑顺昌玻璃钢花盆花器香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

    玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化