|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 moc 于 2018-9-13 22:12 编辑
1、异常的简介
异常是程序在执行期间产生的问题,提供的一种转移程序控制权的机制,与函数机制独立和互补。
函数是一种以站结构展开的上下函数衔接的程序控制系统,异常是另一种控制结构,它依附于栈的结构,却可以同时设置多个异常作为网捕条件,以类型匹配在栈机制中跳跃回馈。
C++ 异常处理涉及到三个关键字:try、catch、throw。
异常处理的基本思想:
1. C++的异常处理机制使得异常的引发和异常处理不必在一个函数中,这样底层函数可以着重解决具体的问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计针对不同类型的异常处理。
2. 异常是专门针对抽象编程的一系列错误处理,C++中不能借助函数机制,因为栈结构的本质是先进后出,依次访问,无法跳跃,但错误处理机制遇到错误可以转到若干级之上进行错误处理。
3. 异常超脱于函数机制,决定了其对函数的跨越式回跳。即异常跨越函数。
2、异常的基本语法
- throw 表达式; // 抛出异常
- //捕获并处理异常
- try
- {
- // 保护代码
- }catch( ExceptionName e1 )
- {
- // catch 块
- }catch( ExceptionName e2 )
- {
- // catch 块
- }catch( ... ) //其他未知异常
- {
- // catch 块
- }
复制代码
1. 若有异常则通过throw操作创建一个异常对象并抛掷;
2. 将可能抛出的异常的程序嵌在try块中,try块内为保护代码。
3. catch子句在try之后,按顺序进行检查,匹配捕获并进行异常处理(或继续抛异常);
4. try语句没有发生异常,则跳过catch子句继续向下执行;
5. 如果没有找到匹配的catch,即抛出的异常无人接受,激发最后一道防线,terminate函数(可修改),该函数引起运行终止和abort函数。
6. 类的构造函数无返回类型,不能通过返回值报告运行状态,可通过异常解决。
7. 异常机制与函数机制互不干涉,异常的捕捉方式是基于类型匹配,捕捉相当于函数返回类型匹配,而不是函数参数匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题。
8. 异常匹配严格按照类型匹配。匹配苛刻程度与模板一样,不允许隐式类型转换。
- void divide(int x, int y)
- {
- if (y == 0) // 0为除数
- {
- throw x; // 抛出 int类型 异常
- }
- cout << "Divide结果:" << x / y << endl;
- }
- void myDivide0(int x, int y)
- {
- divide(x, y);
- }
- // 发生的异常必须在函数中处理,否者会产生函数中断
- int main()
- {
- try
- {
- myDivide0(10, 2);
- myDivide0(123, 0);
- }
- catch (int e) // 捕获int型异常
- {
- cout << e << "被零除" << endl;
- }
- catch (...) // 捕获漏网之鱼
- {
- cout << "其他未知的异常!" << endl;
- cout << "我接受了异常,但我没有处理,我继续往外扔";
- throw;
- }
- system("pause");
- return 0;
- }
复制代码
3、栈解旋
异常抛出后,从进入try块起到异常被抛出前,这期间在栈上的构造的所有对象都会被析构,析构的顺序和构造的顺序相反,这一过程即 栈解旋 。
函数抛出异常限定,可以在定义函数之后加throw说明。
- class Test
- {
- public:
- Test(int a = 0, int b = 0)
- {
- this->a = a;
- this->b = b;
- cout << "构造函数do\n";
- }
- ~Test()
- {
- cout << "析构函数do\n";
- }
- private:
- int a;
- int b;
- };
- void myDivide()
- {
- Test t1(1, 2), tr2(3, 4); // 测试t1,t2的析构顺序
- cout << "myDivide...发生异常\n";
- throw Test();
- }
- void myDivide12() throw (int , char, char*) //该函数只能抛出int,char,char*类型的异常
- {
- throw Test();
- }
- void myDivide2() throw() // 该函数不会抛出任何异常
- {
- throw Test(); // 非要抛出时有警告。
- }
- int main()
- {
- try
- {
- myDivide();
- }
- catch (int a)
- {
- cout << "int类型 异常\n";
- }
- catch (...)
- {
- cout << "未知 异常\n";
- }
- system("pause");
- return 0;
- }
复制代码
4、异常变量的生命周期
throw “aaa”; 是抛出的char*类型。
对于抛出类对象:
1. 如果 接受异常的时候 使用一个异常变量,则执行copy构造函数构造异常变量;
2. 使用引用的话 会直接使用throw时候的那个对象
3. 使用指针接的话,如果抛出时不new一个对象的话,会形成参野指针;
最终结论:类对象发生异常时,使用引用比较合适
5、异常的层次结构
即继承在异常中的应用
对于同一种类型的异常;异常派生,按引用传递异常。
6、C++ 标准的异常
C++ 提供了一系列标准的异常,定义在 <exception> 中,我们可以在程序中使用这些标准的异常。它们是以父子类层次结构组织起来的,如下所示:
传送门
|
|