异常是一种程序控制机制,与函数机制独立和互补
1.若有异常则通过throw操作创建一个异常对象并抛出;
2.将可能抛出的异常程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
3.如果在保护执行段执行期间没有引起异常,那么在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句执行下去。
4.catch子句按照其在try块后出现的顺序检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
5.如果匹配的处理器没有找到,则运行函数的terminate将被自动调用,其缺省功能是调用abort终止程序。
6.处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔。
基本语法:
#include<iostream> using namespace std; //发生异常之后,是抛出跨函数的 void divide(int x, int y) { if (y == 0) { throw x;//抛出int类型异常 } cout << "x/y = " << x / y << endl; } void myDivide(int x,int y) { divide(x, y); } int main() { try { //divide(10, 2); //divide(100, 0); myDivide(100, 0); } catch (int e) { cout << e << "被0除" << endl; } catch(...)//其他类型的异常 { cout << "其他未知类型异常" << endl; } system("pause"); return 0; }
抛出的异常不处理,程序会异常中断:
接受异常后还可以继续在处理中抛出异常。
catch异常时,按照类型catch。
异常捕捉严格按照类型匹配:
int main() { try { throw 'Z'; } catch (int e) { cout << "捕获int类型的异常" << endl; } catch (...) { cout << "捕获未知类型的异常" << endl; }; system("pause"); return 0; }
结果为:
可见 并没有处理隐式的类型转换,严格按照类型抓取。
异常处理的基本思想:
1.c++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层函数可以着重的解决具体问题,而不必过多的考虑异常的处理。上层调用者可以在适当的位置设计对不同类型异常的处理。
2.异常时专门针对抽象编程中的一系列错误处理的,c++中不能借助函数机制,因为栈结构的本质时先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试。如图:
3.异常超脱于函数机制,决定了其对于函数的跨越式回跳。
4.异常跨越函数。
栈解旋
异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序和构造的顺序相反,这一过程称为栈的解旋(unwinding)。
举例:
#include<iostream> using namespace std; class Test3 { public: Test3(int a = 0,int b =0) { cout << "构造函数do " << endl; this->a = a; this->b = b; } ~Test3() { cout << "析构函数do " << endl; } private: int a; int b; }; void myDivide() { Test3 t1(1, 2), t2(3, 4); cout << "myDivied函数即将发生异常 " << endl; throw 1; } int main() { try { myDivide(); } catch (int e) { cout << e << "int类型异常 " << endl; } catch (...)//其他类型的异常 { cout << "其他未知类型异常 " << endl; } system("pause"); return 0; }
根据上述规则,运行结果为:
异常接口的申明:
1.为了加强语法的可读性,可以在函数申明中列出可能抛出的所有异常类型,例如:void func() throw (A,B,C,D);//这个函数能且只能抛出类型为ABCD及其子类型的异常(多态)。
2.如果没有申明,可以抛出任何类型的异常。
3.一个函数不抛出任何类型的异常可以申明为:void func() throw();
4.如果一个函数抛出了它的异常接口申明所不允许抛出的异常,程序就会异常结束。