异常处理
来源:互联网 发布:mac svn图形化界面 编辑:程序博客网 时间:2024/06/05 11:53
----------------siwuxie095
一般的语法知识都是在正常状态下使用的,而异常处理
则是在非正常状态下使用的
异常处理
有人可能会问,在 C++ 中什么是异常,又如何进行处理?
所谓异常,就是程序在运行过程当中所出现的错误
显然,错误并不是我们所希望看到的,但是在某些情况下,
这种错误却会出现,出现后就必须要处理
不处理,就会出现程序崩溃的情况,而崩溃这种情况更是
我们不愿意看到的
对程序进行异常处理,其实就是对可以预见的错误进行
合理的安排
如果做出的安排合理,并能够给出人性化的提示,使用者
就不会觉得突兀
使用者就会根据提示做相应的操作,如:网线没插好,
或内存不足,这样使用者就会非常容易的接受你给他
的提示,并根据提示使得程序能顺利的继续向下运行
如果有些异常没有预料到,那么就会直接抛给系统
系统是很粗暴的,它会将程序直接杀死,对于用户来说,
所看到的现象就是程序直接崩溃掉,而崩溃是我们最不
愿意看到的
程序频繁地崩溃,对于开发者来说,简直就是一场噩梦
如何来进行异常处理呢?
需要用到关键字:try … catch … 和 throw
try 即 尝试运行正常的逻辑,如果在运行正常逻辑时,
出现异常,就会通过catch 将其捕获,捕获之后,再
去对出现的异常进行处理
throw 即 抛出,具体到这里,即 抛出异常,抛出之后,
被catch 捕获,捕获之后,再进行处理
即将主逻辑放在try 中,而将异常处理逻辑放在 catch 中,
看上去非常整齐,对于阅读程序的人来说,也会非常理解你
的程序了
异常处理在C++ 中的工作方式:
定义 3个函数:f1()、f2()、f3(),并用 f2() 来调用 f1(),
用 f3() 来调用 f2()
如果f1() 在运行过程中出现了异常,那么它就会把异常向上抛,
抛给它的调用者f2(),如果 f2() 可以处理,则处理完成,如果
处理不了,就继续向上抛,抛给它的更上层
因为f3() 调用了 f2(),所以,作为更上层的f3() 就会捕获到异
常,捕获之后就会进行相应的处理,如果处理不了,就继续向
上抛,直到有函数可以处理
如果所有的函数都不能处理,就会抛到操作系统,操作系统就会
进行粗暴地干预了
看如下实例:
定义函数fun1():
函数体中写出了throw 1;,这里只是简单的抛出了一个数字 1,
实际的程序当然不能这么写,肯定要写很多正常的逻辑,当运行
到一个我们并不愿意看到的逻辑分支时,才通过throw 抛出异常
在main() 函数中:
通过try … catch … 块来进行异常的捕获:
将 fun1() 的函数调用放在try 块中,如果它能正常的运行完成,
那么就会执行 catch 块下面的代码,而 catch 块得不到执行
如果 fun1() 不能正常的完成自己的主逻辑,而在运行的过程中
不幸出现问题,抛出了1,就必须要用catch 来捕获它,捕获
之后,就可以在 catch 块中进行相应的处理
在 try 块中,如果运行到 fun1() 出现了异常,那么 fun1() 后面
的代码将不会得到运行
另外,注意:在fun1() 中所抛出的是数字1,它是 int 类型的,
在catch 后的括号中写上 int 才能捕获,如果抛出的是0.1,就
应该用double 来进行捕获
对于try … catch … 来说,它可以不是 一对一 的,可以是一对多 的
对于一个try 来说,里面有相应的主逻辑,主逻辑在运行过程中,
可能在第一行代码抛出异常,也可能在第三行代码抛出异常 …
抛出的异常可能是int 类型的,也可能是 double 类型的,还有
可能是其它类型的
这时,就要根据不同的异常来做相应的处理,这种处理就非常的
细致了
如:接到int 类型的异常,就要针对这种情况做相应的处理,告诉
用户怎么样了,用户就会根据你的提示帮助程序正常的往下运行
如果以上的所有的catch 块,如:catch(int){}、catch(double){},
都不能捕获到相应异常,最后的catch 块可以为大家兜底,注意写
法:catch(…){}
这种写法就是说:我可以捕获所有的异常,尽管来吧,所有的异常
我通通可以处理
但是,这种处理很野蛮,因为我们不分青红皂白,没有细致划分,
全部一刀切的在catch(…){}中写相应的处理代码,无非就是告诉
用户:你出错了,只能关闭
所以,不建议直接写一个try 后马上跟一个 catch 加三个点,而是
在前面所有情况都处理不了,已经万般无奈了,才使用catch(…){}
捕获异常,进行最后的挣扎
在上面的例子中有一个特点:所抛出的异常虽然是一个值,但捕获时,
只是一种数据类型,如果想要捕获这个值该怎么办呢?
看如下实例:
定义函数getChar(),传入参数分别是字符串和下标,想要从字符串
中拿到对应下标的字符,但无法保证传入进来的下标比字符串长度短
如果下标比字符串的长度还长,就要通过throw 将异常抛出,告诉
用户当前传入的下标是非法的
采用下面的方式拿到throw 出来的字符:
在catch 中,写的是string& aval,即 取引用,此时如果传入字符串
hello world 和 下标 100,定然会抛出异常:invalid index!
这时就能通过 catch 拿到相应的值,并打印出来,清晰的告诉用户你
的下标传错了
注意:如果在ch=getChar(str,100); 这一行代码就抛出了异常,那么
下一行代码cout<<ch<<endl;就得不到运行
在C++ 中常见的异常:
异常处理与多态的关系
多态和异常处理有着非常紧密的联系,如下:
定义一个异常类:Exception,假设把它定义为一个接口类,在其中
定义一些打印的方法或异常处理的方法
然后通过细分的子类来继承接口类Exception,当抛出子类对象时,
就都可以用这个父类去捕获了
看如下实例:
在 fun1() 中进行逻辑处理的过程中,不幸抛出了异常 SizeErr,
同理,在fun2() 中进行逻辑处理时也抛出了异常 MemoryErr
二者都是 Exception 的子类,此时捕获异常的方法:
不论是 fun1() 还是 fun2(),都可以通过 try … catch … 块来捕获
异常,其中,关键是catch 块中使用了父类 Exception,这时就可
以捕获到 fun1() 和 fun2() 中所抛出的子类对象,并通过子类对象
去调用相应的虚函数
程序:
Exception.h:
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <iostream>
using namespace std;
//接口类 Exception
class Exception
{
public:
virtualvoid printException()=0;
//其实,纯虚析构函数因为比较特殊,在接口类中,
//也可以写为 virtual ~Exception(){}
//这样就不用在 Exception.cpp 中单独为它实现了
virtual ~Exception() =0;
};
#endif
Exception.cpp:
#include"Exception.h"
//因为将Exception类改为了接口类,
//printException()就不需要实现了
//
//void Exception::printException()
//{
// cout << "Exception--printException" << endl;
//}
//注意:
//接口类的纯虚析构函数比较特别,需要进行实现,即有函数体
//(接口类中普通的纯虚函数是没有函数体,不需要实现的)
Exception::~Exception()
{
}
IndexException.h:
#ifndef INDEX_EXCEPTION_H
#define INDEX_EXCEPTION_H
#include"Exception.h"
class IndexException :public Exception
{
public:
virtualvoid printException();
virtual ~IndexException(){}
};
#endif
IndexException.cpp:
#include"IndexException.h"
void IndexException::printException()
{
cout <<"提示:下标越界!" << endl;
}
main.cpp:
#include <stdlib.h>
#include"IndexException.h"
void test1();
void test2();
void test3();
void test4();
//抛出的异常只有被捕获到才能进行合理的处理
//或者说你有能力对其进行处理
//
//如果抛出的异常捕获不到,等待计算机替你处理,
//系统就会非常粗暴,你的程序就会崩溃掉
int main(void)
{
try
{
test1();//换为 2 3 4
}
//虽然不能实例化接口类的对象,但可以使用
//接口类的对象引用和对象指针
catch (Exception &e)
{
e.printException();
}
catch (int)
{
cout <<"exception--int" << endl;
}
catch (double &e)
{
cout <<"exception--double:" << e << endl;
}
catch (...)//兜底用 catch(...){}
{
cout <<"exception" << endl;
}
system("pause");
return0;
}
void test1()
{
throw IndexException();
}
void test2()
{
throw10;
}
void test3()
{
throw0.1;
}
void test4()
{
char ch ='#';
throw ch;
}
【made by siwuxie095】
- 异常处理+异常+处理异常+自定义异常
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- 异常处理
- [C/C++]_[初级]_[关于Gdiplus::Bitmap使用的注意事项]
- Android Studio安装过程中Building gradle project info 一直不动
- 我眼中的MVC模式
- 【模拟】洛谷 P1067 多项式输出
- BZOJ 1483: [HNOI2009]梦幻布丁 链表或者平衡树启发式合并
- 异常处理
- greenDAO3 中使用关系
- 汉诺塔 (杭电acm2064)
- jQuery之Callbacks函数功能测试
- leetcode118 Pascal's Triangle
- 【DP】洛谷 P1064 金明的预算方案
- Scrapy用mysql存储的小技巧
- 设计模式之备忘录模式
- 布局css 标签重置以及类的初始化模板