C++面向对象程序设计 - 异常处理

        在C++发展后期,加了一些功能,作为工具来使用,其中主要有模板(包括函数模板和类模板)、异常处理、命名空间和运行时类型识别,以帮助程序设计人员更方便地进行程序设计和调试工作。

        程序中常见的错误有两大类:语法错误和运行错误。在编译时,编译系统能发现程序中的语法错误(如关键字拼写错误,变量名未定义,语句末尾缺分号,括号不配对等),编译系统会告知用户在第几行出错。由于是在编译阶段发现的错误,因此这类也称为编译错误。

        有的程序虽然能通过编译,也能投入运行。但是在运行过程中会出现异常,得不到正确的运行结果,甚至导致程序不正常终止,或出现死机现象。例如:

  • 在一系列计算过程中,出现除数为0的情况。
  • 内存空间不够,无地实现指定的操作。
  • 无法打开输入文件,因而无法读取数据。
  • 输入数据时数据类型有错。

一、异常处理的方法

        C++面对程序过于复杂和庞大的异常处理时,采取办法是:如果在执行一个函数过程中出现异常,可以不在本函数立即处理,而是发出一个信息,传给它的上一级(即调用它的函数),它的上级捕捉以这个信息后进行处理。如果上一级函数也不能处理,就再传给其上一级,由其上一级处理。如此逐级上送,如果到最高一级还无法处理,最后只好异常终止程序的执行。

        C++处理异常的机制是由3个部分组成的,即检查(try)、抛出(throw)和捕捉(catch)。把需要检查的语句放在try块中,throw用来当出现异常时发出(形象称为抛出,throw的意思是抛出)一个异常信息,而catch则用来捕捉异常信息,旭果捕捉到了异常信息,就处理它。

        这里将前面讲的计算三角形面积程序修改一下,使用try...catch来抛出异常信息。

area = \sqrt{s(s-a)(s-b)(s-c)}

s=\frac{a+b+c}{2}

        示例代码如下:

#include <iostream>
#include <cmath>
using namespace std;
// 计算三角形面积
double triange(double a, double b, double c){double s = (a + b + c) / 2;if(!((a + b >= c) && (b + c >= a) && (c + a >= b))) throw a;return sqrt(s * (s - a)*(s - b)*(s - c));
}int main(){double a, b, c;		//定义变量cout <<"Please enter a value for the three sides of the triangle:" <<endl;try{do{cin >>a >>b >>c;cout <<"Area of a triangle is " <<triange(a, b, c) <<endl;} while(a > 0 && b > 0 && c >0);} catch(double){cout <<"a=" <<a <<", b=" <<b <<", c=" <<c <<", that is not a triangle!" <<endl;cout <<"end" <<endl;}return 0;
}

        运行结果如下图:

二、语法

        throw语句一般是由throw运算符和一个数据组成的,其形式为

throw 表达式;

        try-catch的结构为

try{

        // 被检查的语句

} catch( 异常信息类型 [变量名] ) {

        // 进行异常处理的语句

}

说明:

(1)被检测的函数必须放在try块中,否则不起作用。

(2)try块和catch块作为一个整体出现,catch块是try-catch结构是的一部分,必须紧跟在try块之后,不能单独使用,二者之间不能插入其他语句。

(3)try和catch块中必须有用花括号括起来的复合语句,即使花括号内只有一个语句,也不能省略花括号。

(4)一个try-catch结构中只能有一个try块,但却可以有多个catch块,以便与不同的异常信息匹配。代码如下:

try{//...
} catch(double){//...
} catch(int){//...
} catch(char){//...
}

(5)catch后面的圆括号中,一般只写异常信息的类型名,代码如下:

try{//...
} catch(double){//...
}

(6)catch还可以有另外一个写法,即除了指定类型名外,还可以指定变量名,代码如下:

try{//...
} catch(double a){cout <<"Error Value:" <<a <<endl;
}

(7)如果在catch子句中没有指定异常信息的类型,而用了删节号“...”,则表示它可以捕捉任何类型的异常信息,代码如下:

try{//...
} catch(...){cout <<"All type error" <<endl;
}

(8)try-catch结构可以与throw出现在同一个函数中,也可以不在同一函数中。当throw抛出异常信息后,首先在本函数中寻找与之匹配的catch,如果在本函数中无try-catch结构或找不到与之匹配的catch,就转到其上一层去处理,如果其上一层也无try-catch结构或找不到与之匹配的catch,则再转到更上一层的try-catch结构去处理,也就是说转到离开出现异常最近的try-catch结构去处理。

(9)在某些情况下,在throw语句中可以不包括表达式,代码如下:

throw;

(10)如果throw抛出的异常信息找不到与之匹配的catch块,那么系统就会调用一个系统函数terminate,使程序终止运行。

三、在函数声明中进行异常情况处理

        为了便于阅读程序,使用户在看程序时能够知道所用的函数是否会抛出异常信息以及异常信息可能的类型,C++允许在声明函数时列出可能抛出的异常类型。如上面的三角形面积计算函数,可以修改为:

// 已废弃(不推荐使用)
double triange(double a, double b, double c) throw(double)

        或者可以抛出多类型int,double,float或char类型的异常信息。代码如下:

// 已废弃(不推荐使用)
double triange(double a, double b, double c) throw(int, double, float, char)

        不过,在 C++11 及以后的版本中,函数声明中的异常规格(exception specifications)已经被弃用,并建议使用 noexcept 关键字来替代。noexcept 关键字用于指示函数是否保证不抛出任何异常。代码修改后如下:

// 使用 noexcept(false)(与 throw() 类似,推荐使用)
double triange(double a, double b, double c) noexcept{ double s = (a + b + c) / 2;if(!((a + b >= c) && (b + c >= a) && (c + a >= b))) terminate();return sqrt(s * (s - a)*(s - b)*(s - c));
}

        运行结果如下图:

        请注意,如上图可见,如果 noexcept 函数确实抛出了异常,那么程序会调用 std::terminate 来终止,而不是通过常规的异常处理机制(如 catch 块)来处理。

四、在异常处理中处理析构函数

        如果try块中定义了类对象,在建立该对象时需要调用构造函数。在执行try块的过程中如果发生了异常,此时流程立即离开try块。这样流程就有可能离开该对象的作用域转到其他函数,因而应当事先做好结束对象前的清理工作。在C++的异常处理机制会在throw抛出异常信息被catch捕获时,对有关的局部对象进行析构,析构对象的顺序与构造的顺序相反,然后执行与异常信息匹配的catch块中的语句。

        示例代码如下:

#include <iostream>
#include <string>
using namespace std;
// 定义学生类
class Student{private:int num;string name;public:Student(int num, string name): num(num), name(name){}~Student(){cout <<"destructor Student ~" <<num <<endl;		}// 打印学员信息void print(){if(num==0) throw num;		//如果学号为0抛出异常cout <<"num:" <<num <<", name:" <<name <<endl;}	
};int main(){cout <<"main start" <<endl;try{Student s1(1001, "Tom"), s2(0, "John");// 获取两位学员信息s1.print();s2.print();} catch(int n){cout <<"num=" <<n <<", error!" <<endl;}cout <<"main end" <<endl;return 0;
}

        运行后结果如下图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/26150.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【天池科普】1. 为啥人人都要学AI

大家好&#xff01;欢迎来到天池的AI科普系列课程&#xff0c;本期是第一期内容。在这个信息爆炸的时代&#xff0c;人工智能&#xff08;AI&#xff09;不仅是技术进步的标志&#xff0c;更是推动社会向前发展的强大引擎。无论你是AI领域的新手&#xff0c;还是有一定基础的学…

ER实体关系图与数据库模型图绘制

属性分析 1、用户表(user)、用户钱包表(user_wallet)(与user是1对1关系)、用户钱包交易日志表(user_wallet_log)(与user是1对多关系)。 user&#xff1a;用户表通常包含用户的基本信息&#xff0c;例如用户ID&#xff08;主键&#xff09;、用户名、密码&#xff08;通常加密…

【Three.js】知识梳理二:Three.js引用和环境搭建

1.文件包下载和目录简介 1.1 文件包下载 a. 官方网站下载&#xff1a; 访问 Three.js 的官方网站&#xff08;threejs.org/&#xff09;并点击 "Download" 按钮&#xff0c;下载最新版本的文件包。 b. GitHub仓库下载&#xff1a; 访问 Three.js 的 GitHub 仓库&a…

家具板材ENF级甲醛释放量检测 板材甲醛含量测定

ENF级甲醛释放量检测 ENF级是指甲醛释放量非常低的板材&#xff0c;它代表了无醛添加的最高级别。根据最新的国家标准GB/T 39600-2021&#xff0c;ENF级板材的甲醛释放量不得超过0.025 mg/m。这个标准比欧洲的E1级&#xff08;甲醛释放量≤0.124 mg/m&#xff09;和美国的P2标准…

【Redis】解决 Redis 运行在 Protected Mode 下的 DENIED 错误:消除 Redis 受保护模式的完美方案

【Redis】解决 Redis 运行在 Protected Mode 下的 DENIED 错误&#xff1a;消除 Redis 受保护模式的完美方案 大家好 我是寸铁&#x1f44a; 总结了一篇【Redis】解决 Redis 运行在 Protected Mode 下的 DENIED 错误&#xff1a;消除 Redis 受保护模式的完美方案✨ 喜欢的小伙伴…

LangChain Agent(代理)技术分析与实践

LangChain代理是利用大语言模型和推理引擎执行一系列操作以完成任务的工具&#xff0c;适用于从简单响应到复杂交互的各种场景。它能整合多种服务&#xff0c;如Google搜索、Wikipedia和LLM。代理通过选择合适的工具按顺序执行任务&#xff0c;不同于链的固定路径。代理的优势在…

【YOLOv5进阶】——修改网络结构(以C2f模块为例)

一、站在巨人的肩膀上 这里我们借鉴YOLOv8源码&#xff1a; 上期说到&#xff0c;对于网络模块定义详情在common.py这个文件&#xff0c;如Conv、CrossConv、C3f等。本期要修改的需要参考YOLOv8里的C2f模块&#xff0c;它定义在YOLOv8的module文件夹的block.py文件里&#xf…

测试开发面经分享,面试七天速成

1. get、post、put、delete的区别 a. get请求&#xff1a; i. 用于从服务器获取资源。请求参数附加在URL的查询字符串中。 ii. 对服务器的请求是幂等的&#xff0c;即多次相同的GET请求应该返回相同的结果。 iii. 可以被缓存&#xff0c;可以被收藏为书签。 iv. 对于敏感数据不…

高考后的家庭移民新选择

随着高考的落幕&#xff0c;您是否在思考未来的更多可能性&#xff1f;移民&#xff0c;作为一种生活选择&#xff0c;为许多家庭提供了一个全新的生活和教育环境。我们理解&#xff0c;每个家庭都希望为自己的孩子提供最好的未来。 移民国家通常拥有多元和包容的教育体系&…

四川蔚澜时代电子商务有限公司抖音电商服务怎么样?

随着数字经济的蓬勃发展&#xff0c;电商行业已成为推动经济增长的重要引擎。在这个充满变革与机遇的时代&#xff0c;四川蔚澜时代电子商务有限公司凭借对抖音电商的深入理解和专业服务&#xff0c;迅速崛起为行业的佼佼者&#xff0c;引领着潮流营销的新风尚。 四川蔚澜时代…

ARM32开发--串口库封装(初级)

知不足而奋进望远山而前行 目录 文章目录 前言 目标 内容 开发流程 文件目录创建 分组创建 接口定义 完整代码 总结 前言 在嵌入式软件开发中&#xff0c;封装抽取流程和抽取封装策略是非常重要的技术&#xff0c;能够提高代码的复用性和可维护性。本文将介绍如何在文…

这可能是最清晰易懂的 G1 GC 资料

滑动验证页面 概述 G1 (Garbage-First) 于JDK 6u14版本发布&#xff0c;JDK 7u4版本发行时被正式推出&#xff0c;在JDK9时已经成了默认的垃圾回收器&#xff0c;算是CMS回收器的替代 方案&#xff08;CMS在JDK9以后已经废弃&#xff09; G1是一款分代的 (generational)&a…

如何使用C++ STL标准模板库中的算法函数(附源码)

目录 1、概述 2、调用sort函数对列表元素进行排序 3、调用count_if查找满足条件的元素个数 4、调用find_if函数找到目标元素的信息 5、调用remove_copy_if函数搜索满足条件的多个元素 6、总结 VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.…

LeetCode刷题之HOT100之子集

2024/6/11 周二&#xff0c;闷热&#xff0c;很热。两天没有做题了&#xff0c;前天去附近一景点《十八重溪》游玩&#xff0c;去了才知道暂停开放&#xff0c;只能在附近转转了&#xff0c;瀑布是看不到了。昨天在宿舍呆了一天&#xff0c;今天早上起来就来了实验室。补三张图…

端午节,来看看这本应景的“龙舟书”吧!

大家端午安康呀图片~~ 端午节&#xff0c;不仅要吃粽子&#xff0c;还要看龙舟&#xff01;图片 所以&#xff0c;今天就和大家分享一本“龙舟书”——《精进ChatGPT&#xff1a;高效应用实战88例》&#xff01; 不仅和今天的端午节应景&#xff0c;还和当今的AI时代很配图片…

AI Agent 热门的10篇论文

人工智能代理领域广阔,涵盖广泛的主题,包括多代理系统、强化学习、上下文感知系统以及将大型语言模型 (LLMs) 集成到基于代理的系统中。以下是 arXiv 的一些顶级论文,涵盖了人工智能代理的各个方面: A Framework For Intelligent Multi Agent System Based Neural Network …

Python 基础语法详解(四)

Python 基础语法详解&#xff08;四&#xff09; Python 条件语句最简单的 if 语句基本的 if 语句实战&#xff1a; 复杂 if 语句实战&#xff1a; 看一看 elif 的好处题目&#xff1a;代码实现&#xff1a; 三元表达式格式为&#xff1a;实操&#xff1a; Python 条件语句 在…

Windows 托盘图标实现类封装及使用(附源码)

在系统桌面右下角的托盘区域,创建一个托盘图标,已经是很多软件的标配了,特别是IM即时通讯软件,要在托盘图标上显示来消息时的闪动头像。 其实托盘图标创建很简单,使用起来也比较方便,主要是调用Shell_NotifyIcon API函数,传入不同参数表示对应的操作: 1)NIM_AD…

synchronized 的底层实现

用户态与内核态 JDK 早期&#xff0c;synchronized 叫做重量级锁&#xff0c; 因为申请锁资源必须通过 kernel&#xff08;指大多数操作系统的核心部分&#xff09;&#xff0c;系统调用。 ;hello.asm ;write(int fd, const void *buffer, size_t nbytes)section datamsg db …