c++--异常处理

异常处理

异常处理的任务

  • 程序中常见的错误有两类:
    1. 语法错误
      在编译时,编译系统能发现程序中的语法错误,编译系统会告知用户在第几行出错,是什么样的错误。又称为编译错误。
    2. 运行错误
      另外一些程序能正常通过编译,也能投入运行。但是在运行过程中会出现异常,得不到正常的运行结果,甚至导致程序不正常终止,或出现死机现象。
  • 在设计程序中,应当事先分析程序运行时可能出现的各种意外情况,并分别制定相应的处理方法,这就是异常处理的任务。

异常处理的基本思想

在这里插入图片描述

异常处理的方法

c++处理异常的机制有3部分组成:

  • 检查(try)
    把需要检查的语句放在try块中
  • 抛出(throw)
    当出现异常时发出一个异常信息
  • 捕捉(catch)
    捕捉异常信息,若捕捉到异常,就处理它。
#include <iostream>
#include <cmath>
using namespace std;
int main() {
	double triangle(double, double, double);
	double a, b, c;
	cin >> a >> b >> c;
	try {
		while (a > 0 && b > 0 && c > 0) {
			cout << triangle(a, b, c) << endl;        //程序执行triangth语句出现异常,后续的语句不会再执行,而是跳到catch块处
			cin >> a >> b >> c;
		}
	}
	catch(double){                                    //发现抛出的异常为double型的a,然后与catch的double类型匹配,便进入catch内,进行处理。处理完catch快内的语句,继续往下执行,不再返回上面未执行的语句。
		cout << "not a triangle" << endl;
	}
	cout << endl;
    return 0;
	/*结果
	    4 5 6
		9.92157
		11 22 18
		98.5187
		1 2 1
		not a triangle

	*/
}
double triangle(double a, double b, double c) {
	if (a + b <= c && b + c <= a && a + c <= b)
       throw a;
	double s = (a + b + c) / 2;
	if (a + b <= c || b + c <= a || a + c <= b)  
		throw a;                                                //检查到异常出现,执行了throw语句后,流程立刻离开本函数,转到其上一级的函数,不再执行后面的语句。
	return sqrt(s*(s - a)*(s - b)*(s - c));
}

异常处理的实现机制

  • throw的语法:
        throw 表达式;
  • try-catch语法:
    try {
        被检查的语句;
	}catch(异常信息类型 [变量名]{
	    进行异常处理的语句;
	}
  • 若有异常则通过throw操作创建一个异常对象并抛掷。
  • 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
  • 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
  • catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
  • 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。
  • 说明:
  1. 被检查的部分必须放入try块中,否则不起作用。

  2. try和catch作为一个整体出现.可以只有try块,但catch块不可以脱离try块独立存在。

  3. try和catch块内的{}不可以省略。

  4. try-catch结构只能有一个try块,但是可以有多个catch块,匹配不同的信息。

  5. catch后面的圆括号中一般只写异常信息的类型名,若还指定了变量名,则抛出的数值会拷贝给变量名。异常信息可以时c++标准的类型,还可以是用户自定义的类型。

    catch(double b){} 则上面抛出的a值会传递给b;

  6. 若catch字句中没有指定异常信息的类型,而用了删节号"···",则表示它可以捕捉任何类型的异常类型。

  7. try-catch可以和catch出现在一个函数中,也可以不在一个函数中。若throw抛出一个异常,先在本函数中寻找与子匹配的catch块,若找不到或者匹配不上,就转到上一层去处理。若上层也找不到或无法匹配,在往上继续转。

  8. 在某些情况下,throw可以不包含表达式,若在catch块中包含”throw“:

    try{
    ···
    }catch(int ){
     throw;
    }
    

    表示将抛出的异常再次原样上抛,给上一级catch块处理。

  9. 若throw抛出的异常找不到匹配的catch,那系统会调用一个系统函数terminate,使程序终止。

在函数声明中进行异常情况指定

  • c++允许在声明函数时列出可能抛出的异常类型。
  • 异常指定时函数声明的一部分,必须同时出现在函数声明和函数定义首行中,否则编译时会报告”类型不匹配“。
    double triangth(double,double,double) throw(inter,double,float,char);
  • 若声明时未列出可能抛出的异常类型,则该函数可以抛出任何类型的异常信息。
    double triangth(double,double,double) ;
  • 若想声明一个不能抛出异常的函数:
    double triangth(double,double,double) throw();
    此时就算函数有throw语句,也不会执行throw语句。程序将非正常停止。
#include<iostream>
using namespace std;
int Div(int x, int y);
int main(){
	try{
		cout << "5/2=" << Div(5, 2) << endl;
		cout << "8/0=" << Div(8, 0) << endl;
		cout << "7/1=" << Div(7, 1) << endl;
	}catch (int){
		cout << "except of deviding zero.\n";
	}
	cout << "that is ok. \n";
}
int Div(int x, int y)throw(int){
	if (y == 0) 
		throw y;
	return x/y;
	/*5/2=2
      except of deviding zero.
      that is ok.
	  */
}

异常处理中的构造与析构

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

  1. 初始化参数。
  2. 将从对应的try块开始到异常被抛掷处之间构造(且尚未析构)的所有自动对象进行析构。
  3. 从最后一个catch处理之后开始恢复执行。
#include<iostream>
using namespace std;
void MyFun(void);
class Expt{
public:
	 Expt() { cout << "我是一个构造函数哦" << endl; }
	~Expt() { cout << "我是一个析构函数哦" << endl; }
	const char* ShowReason() const{
		return "Expt类异常.";
	}
};
class Demo{
public:
	Demo();
	~Demo();
};
Demo::Demo(){
	cout << " 构造 Demo." << endl;
}
Demo::~Demo(){
		cout << " 析构 Demo." << endl;
}
void MyFun(){
	Demo D;
	cout << "在MyFun()中抛掷Expt类异常。" << endl;
	throw Expt();
}
int main(){
	cout << "在main函数中。" << endl;
	try
	{
		cout << "在try块中,调用MyFun()。" << endl;
		MyFun();
	}
	catch (Expt E){
		cout << " 在catch异常处理程序中。 " << endl;
		cout << " 捕获到 Expt 类型异常: ";
		cout << E.ShowReason() << endl;
	}catch (char *str){
	    cout << " 捕获到其他的异常: " << str << endl;
    }
    cout << " 回到 main 函数。从这里恢复执行."<< endl;
    return 0;
}

在这里插入图片描述

#include <iostream>
#include<string>
using namespace std;

class Student {
public :
	Student(int n,string na) {
		cout << "Student::constructor----" << n << endl;
		sno = n;
		name = na;
	}
	~Student() {
		cout << "Student::destory---" <<sno<< endl;
	}
		void getDate();
private:
	int sno;
	string name;
};
void Student::getDate() {
	cout << "in  get_date()  " << endl;
	if (sno == 0) {
		cout << "find exception,throw the exception and out get_date()!" << endl;
		cout << endl;
		throw sno;
	}
	else
		cout << "Student :" << name << "  " << sno << endl;
	cout << "out  get_date()  " << endl;
	cout << endl;
}

void fun() {
	cout << endl;
	cout << "in_fun()" << endl;
	Student s1(1001, "Tom");
	s1.getDate();
	Student s2(0, "YH");
	s2.getDate();
	cout << "out_fun()" << endl;
}

void main() {
	cout << "main begin" << endl;
	try {
		cout << "call fun()" << endl;
		fun();
	}
	catch (int n) {
		cout << "in_catch" << endl;
		cout << "sno==" << n << ",error!" << endl;
		cout << "out_catch;" << endl;
		cout << endl;
	}
	cout << "main end;" << endl;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41498261/article/details/82962765