C++回顾day03---<异常>
一:传统错误处理机制(C中通过函数返回来处理)
int CalcRes(int n, int m, char ch, int& res)
{
int err = ;
switch (ch)
{
case '+':
res = n + m;
break;
case '-':
res = n - m;
break;
case '/':
if (m == )
err = -;
res = ;
break;
case '*':
res = n*m;
break;
} return err;
} void main()
{
int res,err;
err = CalcRes(, , '/', res);
if (err == -)
cout << "calculate error:divide 0" << endl;
system("pause");
}
二:异常处理基本思想
(一)C++异常处理机制使得异常的引发和处理不必过度关注。上层调用者只需要在适当的位置设置对不同类型异常的处理
传统的错误处理,通过返回值判断出错,进行处理,或者一步步向上返回错误码,十分复杂。而异常处理机制只需要在适当位置进行出错捕获可以进行错误处理
(二)异常是专门针对抽象编程中的一系列错误处理的,C++不需要借助函数机制(向C传统错误处理,逐函数返回,无法进行跳跃)
(三)异常超脱于函数机制(函数之间调用需要压栈出栈操作),遇到异常抛出,可以跨越式回跳,而不需要逐级出栈处理。
(四)C++异常跨越式回跳:代码实现
int CalcRes(int n, int m, char ch, int& res)
{
int err = ;
switch (ch)
{
case '+':
res = n + m;
break;
case '-':
res = n - m;
break;
case '/':
if (m == )
throw n; //抛出int异常
res = ;
break;
case '*':
res = n*m;
break;
} return err;
} void t3()
{
int res;
CalcRes(5, 0, '/', res); //若是异常抛出后会跨越式会跳--->那么后面的红色代码不会显示,因为不会按出栈方式继续执行
cout << "t3" << endl;
} void t2()
{
t3();
cout << "t2" << endl;
} void t1()
{
t2();
cout << "t1" << endl;
} void main()
{
try
{
t1();
}
catch (int n)
{
cout << n << endl;
}
system("pause");
}
三:C++异常处理的实现
(一)抛出异常: throw 表达式;
void func()
{
...
throw 表达式;
...
}
(二)捕获并处理异常:try...catch...
try
{
捕获代码块
例如:调用func()
}
catch(异常类型声明)
{
异常处理语句
}
catch(类型 (形参))
{
...
}
...
(三)异常处理步骤
1.若有异常:可以通过throw操作创建一个异常对象并抛出
2.将可能有异常的代码段嵌入try块进行捕获。
3.若是没有抛出异常,则跳过catch语句继续向下执行
4.若是捕获到异常抛出,则执行相关catch语句处理异常,或者若是玉带处理不了的异常可以继续throw向上抛出。
5.若是到最后,匹配的处理器都未找到,则会调用系统函数terminate(调用abort终止程序)
(四)案例一:正常捕获异常
int divide(int x, int y)
{
if (y == )
throw x; //抛出int整型异常
return x / y;
} void main()
{
try
{
cout << "8/2=" << divide(, ) << endl;
cout << "5/0=" << divide(, ) << endl;
}
catch (int e) //捕获int整型异常
{
cout << e << " is divide by zero" << endl;
}
catch (...) //...是捕获所有异常
{
cout << "catch all exception" << endl;
}
system("pause");
}
(五)案例二:异常未捕获,触发系统调用abort终止
class A
{ }; int divide(int x, int y)
{
if (y == )
throw A(); //抛出A类异常
return x / y;
} void main()
{
try
{
cout << "8/2=" << divide(, ) << endl;
cout << "5/0=" << divide(, ) << endl;
}
catch (int e) //捕获int整型异常
{
cout << e << " is divide by zero" << endl;
}
//catch(A) //未捕获
system("pause");
}
(六)修改系统默认行为set_terminate--->可以用catch(...)捕获全部,来代替
#include <exception> class A
{ }; int divide(int x, int y)
{
if (y == )
throw A(); //抛出A类异常
return x / y;
} void my_Terminate()
{
cout << "exec myself terminate" << endl;
exit(-);
} void main()
{
set_terminate(my_Terminate); //修改系统默认行为(会在系统调用abort之前执行,若是这里异常还没有被处理,那么还是会调用abort)
try
{
cout << "8/2=" << divide(, ) << endl;
cout << "5/0=" << divide(, ) << endl;
}
catch (int e) //捕获int整型异常
{
cout << e << " is divide by zero" << endl;
}
//catch(A) //未捕获
system("pause");
}
在vs下未实现,vc++似乎可以实现代码。所以我们一般不要使用它
(七)捕获严格按照抛出类型匹配
例如:
throw int;
catch(char);是无法捕获的
四:栈解旋
在异常被抛出后,即throw异常,之后会对栈上的所有对象进行自动析构。析构顺序与构造相反,这一过程叫做栈的解旋
class A
{
public:
A()
{
cout << "A construct" << endl;
} ~A()
{
cout << "A distruct" << endl;
}
}; class B
{
public:
B()
{
cout << "B costruct" << endl;
} ~B()
{
cout << "B distruct" << endl;
}
}; void divide(int n, int m)
{
B b; //对象二后入栈
if (m == )
throw n;
} void t1()
{
A a; //对象一先入栈
divide(, );
} void main()
{
try
{
t1();
}
catch (int e)
{
cout << e << " divide zeor is err" << endl;
} system("pause");
}
五:异常接口声明
(一)为了增强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型(也只能抛出这几个类型)
void func() throw(A,B,C,D); //这个函数只能抛出这几个类型
(二)若是函数声明中没有包含任何异常接口声明,那么这个函数可以抛出任何类型的异常
(三)一个不允许抛出任何异常的函数
void func() throw();
(四)若是一个函数抛出了他的异常接口所不允许的异常,unexpected函数会被调用,该函数默认行为会调用terminate函数终止程序
六:异常类型和异常变量的生命周期
(一)throw的异常是有类型的,可以是数字,字符串,类对象,字符...。
void t1(int flag) throw(int,char,double,char*,A) //进行异常接口声明
{
if (flag == )
throw ; //抛出整型
else if (flag == )
throw "string throw"; //抛出字符串
else if (flag == )
throw 'c'; //抛出字符
else if(flag == )
throw 1.1;
else
throw A(); //抛出类对象
} void main()
{
try
{
//t1(0);
//t1(1);
//t1(2);
t1();
}
catch (int e)
{
cout << e << endl;
}
catch (char c)
{
cout << c << endl;
}
catch (char* s)
{
cout << s << endl;
}
catch(double b)
{
cout<<b<<endl;
} catch (A a)
{
cout << "catch obj a" << endl;
}
}
(二)异常变量的生命周期(异常变量周期会在throw之后被释放,catch获取的是一个新的拷贝变量)
七:标准异常类
基类Exception中提供了一个what函数,用于返回错误信息,返回类型const char*
函数声明类型:
virtual const char* what() const throw();
(一)标准异常类的继承关系
其中runtime_error是运行时异常,难以检测。
logic_error是逻辑错误,可能IDE都会检测出来,易发现
logic_error和runtime_error两个类及其派生类都有一个接受const string&形参的构造函数---->说明我们可以自己写错误提示信息
(二)异常类所在的头文件和含义
(三)标准异常类的使用(模拟一个)
class A
{
public:
A(int a)
{
if (a > )
throw out_of_range("age to long");
} ~A()
{
cout << "A distruct" << endl;
}
}; void main()
{
try
{
A a();
}
catch (out_of_range e)
{
cout << e.what();
}
system("pause");
}
(四)注意:使用exception &e只能捕获其基类为Exception及其子类的所有异常。所以要捕获所有异常可以使用catch(...)更好(但是没有what方法,可以自己定义)
C++回顾day03---<异常>的更多相关文章
- Java I/O(二)其他常用的输入输出流PrintStream等、标准流重定向
四.FilterOutputStream.PrintStream PrintStream是继承自FilterStream类的,例如标准输出流System.out就是著名的PrintStream类对象. ...
- java.IO输入输出流:过滤流:buffer流和data流
java.io使用了适配器模式装饰模式等设计模式来解决字符流的套接和输入输出问题. 字节流只能一次处理一个字节,为了更方便的操作数据,便加入了套接流. 问题引入:缓冲流为什么比普通的文件字节流效率高? ...
- Java中IO流,输入输出流概述与总结
总结的很粗糙,以后时间富裕了好好修改一下. 1:Java语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在java.io包中.其中, 所有输入流类都是抽象类InputStream(字节输入 ...
- 第27章 java I/O输入输出流
java I/O输入输出流 1.编码问题 import java.io.UnsupportedEncodingException; /** * java涉及的编码 */ public class En ...
- java 对象输入输出流
对象的输入输出流的作用: 用于写入对象 的信息读取对象的信息. 对象的持久化. 比如:用户信息. ObjectInputStream : 对象输入流 ...
- 【转】输入/输出流 - 全面掌握IO
File类: 程序中操作文件和目录都可以使用File类来完成即不管是文件还是目录都是使用File类来操作的,File能新建,删除,重命名文件和目录,但File不能访问文件内容本身,如果需要访问文件本身 ...
- 输入输出流(IO)
输入输出流(IO)文件(File)java.io.File用于表示文件(目录),也就是说程序员可以通过File类在程序中操作硬盘上的文件和目录.File类只用于表示文件(目录)的信息(名称.大小等), ...
- Java输入/输出流体系
在用java的io流读写文件时,总是被它的各种流能得很混乱,有40多个类,理清啦,过一段时间又混乱啦,决定整理一下!以防再忘 Java输入/输出流体系 1.字节流和字符流 字节流:按字节读取.字符流: ...
- JAVA Io 缓冲输入输出流
java中提供带缓冲的输入输出流.在打开文件进行写入或读取操作时,都会加上缓冲,提高了IO读写性能. 1. BufferedInputStream 缓冲输入流 2. BufferedOutputStr ...
- C++输入输出流
一.C++输入输出流的含义 以前所用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上.从操作系统的角度看,每一个与主机相连的输入输出设备都被看作一个文件.程序的输入指的 ...
随机推荐
- libstdc++适配Xcode10与iOS12
编译报错 当你开心得升级完新 macOS,以及新 XCode,准备体验了一把 Dark Mode 编程模式,开心的打开自己的老项目的时候,发现编译不通过了╮(╯_╰)╭ 如果你的工程中如果依赖 lib ...
- 安装ESXi部署OVF详细步骤
整个安装部署过程均在个人环境进行.欧克,我们现在开始. 一.安装ESXi 1.Enter回车 2.Enter回车继续 3.F11,接受继续 4.Enter,回车继续(选择安装ESXi的设备) 5.默认 ...
- LeetCode算法题-Binary Number with Alternating Bits(Java实现)
这是悦乐书的第292次更新,第310篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第160题(顺位题号是693).给定正整数,检查它是否具有交替位:即它的二进制数的任意两 ...
- 5.机器学习——DBSCAN聚类算法
1.优缺点 优点: (1)聚类速度快且能够有效处理噪声点和发现任意形状的空间聚类: (2)与K-MEANS比较起来,不需要输入要划分的聚类个数: (3)聚类簇的形状没有偏倚: (4)可以在需要时输入过 ...
- Scheme来实现八皇后问题(2)
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/9790466.html 作者:窗户 Q ...
- 【Python 16】分形树绘制4.0(利用递归函数绘制分形树fractal tree)
1.案例描述 树干为80,分叉角度为20,树枝长度小于5则停止.树枝长小于30,可以当作树叶了,树叶部分为绿色,其余为树干部分设为棕色. 2.案例分析 由于分形树具有对称性,自相似性,所以我们可以用 ...
- Maven pom.xml中的元素modules、parent、properties以及import
前言 项目中用到了maven,而且用到的内容不像利用maven/eclipse搭建ssm(spring+spring mvc+mybatis)用的那么简单:maven的核心是pom.xml,那么我就它 ...
- Java 8 中为什么要引出default方法
(原) default方法是java 8中新引入进的,它充许接口中除了有抽象方法以外,还可以拥用具有实现体的方法,这一点跟jdk8之前的版本已经完全不一样了,为什么要这样做呢? 拿List接口举例,在 ...
- 正益工作能担起PaaS+SaaS的未来探索吗?
没有竞争,行业没有未来.不参与竞争,企业没有未来.中国企业的类型纷繁复杂,也决定了企业的多样化需求.云计算和移动化的双重叠加,企业管理需要重新梳理,企业业务创新日益频繁,个性化需求日益突出,软件服务商 ...
- CentOS 7 软件安装简记
Install SW Record ================= $ sudo yum install vim-X11.x86_64 $ sudo yum install clang.x86_6 ...