关于异常的几种处理方法:
1、 调用abort()
Abort()函数的原型位于头文件cstdlib.h(或者stdlib.h)中,其典型实现是向标准错误流(即cerr使用的错流),发送abnormal program termination(程序异常终止),然后终止程序。它还返回一个随实现而异的值。
abort()是否刷新文件缓冲区(用于存储读写到文件中的数据的内存区域)取决于实现
但是,也可以使用exit(),该函数刷新文件缓冲区,但不显示信息。
2、 返回错误码
常规错误处理方法,将错误打印出来。
3、 异常机制
异常提供了将控制权从程序的一个部分传递到另一个部分的途径
对异常处理有3个部分组成:
throw语句实际上是跳转,即命令程序跳转到另一条语句。throw关键字表示引发异常,紧随其后的值指出了异常的特征。
catch关键字表示捕获异常,随后是位于括号中的类型声明,它指出了异常处理程序要响应的异常类型,然后是一个花括号括起的代码块,指出要采取的措施。catch关键字和异常处理类型用作标签,指出当异常被引发时,程序应跳到这个位置执行。
try块标识其中特定的异常可能被激活的代码块,它后面跟一个或多个catch块。Try的后面是一个由花括号括起的代码块,表明需要注意这些代码引起的异常。
Demo1:
#include
using namespace std;
double hmean(double a,double b);
int main()
{
double x, y, z;
cout << “Enter two numbers:” << endl;
while (cin>>x>>y)
{
try
{
z = hmean(x, y);
}
catch (const char* s)
{
cout << s << endl;
cout << “Enter a new pair of numbers:” << endl;
continue;
}
cout << “Harmonic mean of” << x << “and” << y << “is” << z << endl;
cout << “Enter next set of numbers” << endl;
}
cout << "bye!" << endl;
getchar();
return 1;
}
double hmean(double a,double b)
{
if (a == -b)
{
throw “bad hmean() arguments:a = -b not allowed”;
}
return 2.0ab / (a+b);
}
/*
执行throw语句类似于执行返回语句,因为它也将终止函数的执行;
但是throw不是将控制权返回给调用程序,而是导致程序沿函数调用序列后退,直到找到包含try块的函数。
在这个例子中,throw将程序控制权返回给main(),程序将在main()中寻找与引发的异常类型匹配的异常处理程序(位于try块的后面)
出现异常时的程序流程:
1、程序在try块中调用hmean()
2、hmean()引发异常,将从而执行catch块,并将异常字符串赋给s
3、catch返回到while循环开始的位置
*/
Demo2:
将对象用作异常类型
//将对象用作异常类型
#include
using namespace std;
class bad_hmean
{
private:
double v1;
double v2;
public:
bad_hmean(int a = 0, int b = 0) :v1(a), v2(b){}
void mesg();
};
inline void bad_hmean::mesg()
{
cout << “hmean(” << v1 << “,” << v2 << "):invalid arguments: a =- b " << endl;
}
class bad_gmean
{
public:
double v1;
double v2;
bad_gmean(double a = 0, double b = 0) :v1(a), v2(b){}
const char* mesg();
};
inline const char* bad_gmean::mesg()
{
return “gmean() arguments should be>=0”;
}
#include
#include
#include “48.cpp”
//函数原型
double hmean(double a,double b);
double gmean(double a,double b);
int main()
{
double x, y, z;
cout << “Enter two numbers:” << endl;
while (cin>>x>>y)
{
try
{
z = hmean(x, y);
cout << “Harmonic mean of” << x << “and” << y << “is” << z << endl;
cout << “Geometric mean of” << x << “and” << y << “is” << gmean(x, y) << endl;
cout << “Enter next set of numbers:”;
}
catch (bad_hmean& bh)
{
bh.mesg();
cout << “Try again” << endl;
continue;
}
catch (bad_gmean& bg)
{
cout << bg.mesg() << endl;
cout << “Values used:” << bg.v1 << “,” << bg.v2 << endl;
cout << “Sorry, you should not get to play any more” << endl;
break;
}
}
cout << “bye!” << endl;
system("pause");
return 1;
}
double hmean(double a,double b)
{
if (a == -b)
{
throw bad_hmean(a,b); //抛出类对象
}
return 2.0ab / (a + b);
}
double gmean(double a,double b)
{
if (a<0 || b<0)
{
throw bad_gmean(a, b);
}
return sqrt(a * b);
}
/*
其他异常特性:
1、控制权返回
2、引发异常时编译器总是创建一个临时拷贝,即使异常规范和catch块中指定的是引用
demo:
class problem{…};
…
void super() throw(problem)
{
…
if (ch_no)
{
problem oops;//创建类对象
throw oops; //抛出类对象
…
}
}
…
try
{
super();
}
catch(problem& p)
{
//…
}
p将指向oops的副本而不是oops本身,这是件好事,因为函数super()执行完毕后,oops将不复存在。
顺便说一句,将引发异常和创建对象组合在一起将更加简单:
throw problem(); //就是将前面创建类对象的那两句 合并在一起
问题:既然throw语句将生成副本,为何代码中使用引用??
回答:1、基类引用可以执行派生类对象。假设有一组通过继承关联起来的异常类型,
则在异常规范中只需列出一个基类引用,它将与任何派生类对象匹配。
重点:catch块的排列顺序应该与派生类顺序相反
demo:
class bad_1{…};
class bad_2 : public bad_1{…};
class bad_3 : public bad_2{…};
…
void duper()
{
…
if(oh_no)
throw bad_1();
if (rats)
throw bad_2();
if (drat)
throw bad_3();
…
}
…
try
{
duper();
}
catch(bad_3& b3)
{
}
catch(bad_2& b2)
{
}
catch(bad_1& b1)
{
}
如果将bad_1&处理程序放在最前面,它将捕获bad_1,bad_2,bad_3;通过按相反的顺序排列,bad_3异常将被bad_3处理程序所捕获
提示:如果有一个异常类继承层次结构,应该这样排列catch块:
将捕获位于层次结构最下面的异常类的catch语句放在最前面,
将捕获基类异常的catch语句放在最后面;
如果不知道调用的函数可能引发哪些异常,方法是使用省略号来表示异常类型,从而捕获任何异常。
catch(…) //三个点,捕获任何异常
{
//
}
*/
/*
exception类
#include
代码可以引发exception异常,也可以将exception类用作基类。
有一个名为what()的虚拟成员函数,它将返回一个字符串,该字符串的特征随实现而异。
了解一下,不做延伸
*/