购物网站价格,找第三方做网站 需要注意,如何做网站客户端,如何自做网站#c primer plus 第15章友#xff0c;异常和其他#xff1a;异常,15.3.3 异常机制 异常,15.3.3 异常机制 文章目录 15.3.3 异常机制15.3.3 异常机制程序清单 15.9error3.cpp15.3.4 将对象用作异常类型程序清单15.10exc mean.h程序清单 15.11error4.cpp 15.3.3 异常机制
15.3.…#c primer plus 第15章友异常和其他异常,15.3.3 异常机制 异常,15.3.3 异常机制 文章目录 15.3.3 异常机制15.3.3 异常机制程序清单 15.9error3.cpp15.3.4 将对象用作异常类型程序清单15.10exc mean.h程序清单 15.11error4.cpp 15.3.3 异常机制
15.3.3 异常机制
下面介绍如何使用异常机制来处理错误。C异常是对程序运行过程中发生的异常情况(例如被0除)的一种响应。异常提供了将控制权从程序的一个部分传递到另一部分的途径。对异常的处理有3个组成部分:
引发异常;使用处理程序捕获异常;使用 try 块。程序在出现问题时将引发异常。例如可以修改程序清单15.7中的hmean()使之引发异常而不是调用 abort()函数。throw语句实际上是跳转即命令程序跳到另一条语句。throw 关键字表示引发异常紧随其后的值(例如字符串或对象)指出了异常的特征。
程序使用异常处理程序(exceptionhandler)来捕获异常,异常处理程序位于要处理问题的程序中。catch关键字表示捕获异常。处理程序以关键字catch开头随后是位于括号中的类型声明它指出了异常处理程序要响应的异常类型:然后是一个用花括号括起的代码块指出要采取的措施。catch 关键字和异常类型用作标签指出当异常被引发时程序应跳到这个位置执行。异常处理程序也被称为 catch块。 try 块标识其中特定的异常可能被激活的代码块它后面跟一个或多个 catch 块。try 块是由关键字 try指示的关键字 try 的后面是一个由花括号括起的代码块表明需要注意这些代码引发的异常。要了解这3个元素是如何协同工作的最简单的方法是看一个简短的例子如程序清单15.9所示。
程序清单 15.9error3.cpp
// error3.cpp -- using an exception
#include iostream
double hmean(double a, double b);int main()
{double x, y, z;std::cout Enter two numbers: ;while (std::cin x y){try { // start of try blockz hmean(x,y);} // end of try blockcatch (const char * s) // start of exception handler{std::cout s std::endl;std::cout Enter a new pair of numbers: ;continue;} // end of handlerstd::cout Harmonic mean of x and y is z std::endl;std::cout Enter next set of numbers q to quit: ;}std::cout Bye!\n;return 0;
}double hmean(double a, double b)
{if (a -b)throw bad hmean() arguments: a -b not allowed;return 2.0 * a * b / (a b);
}
程序说明 在程序清单 15.9中try块与下面类似:
try {
z hmean(x,y);
}
// start of try block
// end of try block如果其中的某条语句导致异常被引发则后面的 catch 块将对异常进行处理。如果程序在 try块的外面调用 hmean()将无法处理异常。 引发异常的代码与下面类似:
if(a -b)
throw bad hmean()arguments:a-b not allowed;其中被引发的异常是字符串“bad hmean()arguments:a-bnot allowed”。异常类型可以是字符串(就像这个例子中那样)或其他C类型:通常为类类型本章后面的示例将说明这一点。执行 throw 语句类似于执行返回语句因为它也将终止函数的执行;但throw 不是将控制权返回给调用程序而是导致程序沿函数调用序列后退直到找到包含ty块的函数。在程序清单15.9中该函数是调用函数。稍后将有一个沿函数调用序列后退多步的例子。另外在这个例子中throw 将程序控制权返回给 main()。程序将在 main()中寻找与引发的异常类型匹配的异常处理程序(位于try 块的后面)。处理程序(或catch块)与下面类似:
catch(char*s)//start of exception handler
std::cout sstd::endl;
sdt::cout Enter anew pair of numbers:;
continue;
//end of handlercatch 块点类似于函数定义但并不是函数定义。关键字 catch 表明这是一个处理程序而 chars则表明该处理程序与字符串异常匹配。s与函数参数定义极其类似因为匹配的引发将被赋给s。另外当异常与该处理程序匹配时程序将执行括号中的代码。 执行完 try 块中的语句后如果没有引发任何异常则程序跳过tny块后面的 catch 块直接执行处理程序后面的第一条语句。因此处理值3和6时程序清单15.9中程序执行报告结果的输出语句。接下来看将 10和-10传递给 hmean()函数后发生的情况。If语句导致 hmean( )引发异常。这将终止 hmean()的执行。程序向后搜索时发现hmean()函数是从 main()中的try块中调用的因此程序查找与异常类型匹配的 catch 块。程序中唯一的一个 catch 块的参数为char因此它与引发异常匹配。程序将字符串“bad hmean( )arguments:a-bnotallowed”赋给变量s然后执行处理程序中的代码。处理程序首先打印 s–捕获的异常然后打印要求用户输入新数据的指示最后执行continue语句命令程序跳过 while循环的剩余部分跳到起始位置。continue使程序跳到循环的起始处这表明处理程序语句是循环的一部分而catch行是指引程序流程的标签(参见图15.2)。 您可能会问如果函数引发了异常而没有ty块或没有匹配的处理程序时将会发生什么情况。在默认情况下下程序最终将调用 abort()函数但可以修改这种行为。稍后将讨论这个问题。
15.3.4 将对象用作异常类型
通常引发异常的函数将传递一个对象。这样做的重要优点之一是可以使用不同的异常类型来区分不同的函数在不同情况下引发的异常。另外对象可以携带信息程序员可以根据这些信息来确定引发异常的原因。同时catch 块可以根据这些信息来决定采取什么样的措施。例如下面是针对函数 hmean()引发的异常而提供的一种设计:
class bad_hmean
{
private :
double vl;
double v2;
public:bad hmean(int a0,intb0):v1(a)v2(b){}
void mesg();
}
inline void bad hmean::mesg()
std::cout hmean( vl , v2 ):invalid arguments:a-bn;
}
可以将一个 bad hmean 对象初始化为传递给函数hmean()的值而方法 mesg()可用于报告问题(包括传递给函数 hmena()的值)。函数hmean()可以使用下面这样的代码:
if(a -b)
throw bad hmean(a,b);上述代码调用构造函数bad hmean()以初始化对象使其存储参数值。程序清单 15.10和 15.11添加了另一个异常类 bad_gmean 以及另一个名为 gmean()的函数,该函数引发bad gmean 异常。函数 gmean()计算两个数的几何平均值即乘积的平方根。这个函数要求两个参数都不为负如果参数为负它将引发异常。程序清单15.10是一个头文件其中包含异常类的定义:而程序清单 15.11是一个示例程序它使用了该头文件。注意try块的后面跟着两个 catch 块:
try
{
// start of try block
...
}// end of try block
//start of catch blockcatch(bad hmean bg)
catch(bad gmean hg)
{
//end of catch block
}如果函数 hmean()引发 bad_hmean 异常第一个 catch块将捕获该异常;如果 gmean()引发bad_gmean异常异常将逃过第一个catch块被第二个catch 块捕获。
程序清单15.10exc mean.h
// exc_mean.h -- exception classes for hmean(), gmean()
#include iostreamclass bad_hmean
{
private:double v1;double v2;
public:bad_hmean(double a 0, double b 0) : v1(a), v2(b){}void mesg();
};inline void bad_hmean::mesg()
{ std::cout hmean( v1 , v2 ): invalid arguments: a -b\n;
}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\n;
}
程序清单 15.11error4.cpp
//error4.cpp ?using exception classes
#include iostream
#include cmath // or math.h, unix users may need -lm flag
#include exc_mean.h
// function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
int main()
{using std::cout;using std::cin;using std::endl;double x, y, z;cout Enter two numbers: ;while (cin x y){try { // start of try blockz 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 q to quit: ;}// end of try blockcatch (bad_hmean bg) // start of catch block{bg.mesg();cout Try again.\n;continue;} catch (bad_gmean hg) {cout hg.mesg();cout Values used: hg.v1 , hg.v2 endl;cout Sorry, you dont get to play any more.\n;break;} // end of catch block}cout Bye!\n;// cin.get();// cin.get();return 0;
}double hmean(double a, double b)
{if (a -b)throw bad_hmean(a,b);return 2.0 * a * b / (a b);
}double gmean(double a, double b)
{if (a 0 || b 0)throw bad_gmean(a,b);return std::sqrt(a * b);
}
下面是程序清单15.10和15.11组成的程序的运行情况错误的 gmean()函数输入导致程序终止:
首先,bad_hmean 异常处理程序使用了一条 continue语句,而bad_gmean 异常处理程序使用了一条 break语句。因此如果用户给函数hmean()提供的参数不正确将导致程序跳过循环中余下的代码进入下一次循环;而用户给函数 gmean()提供的参数不正确时将结束循环。这演示了程序如何确定引发的异常(根据异常类型)并据此采取相应的措施。 其次异常类 bad_gmean 和 bad hmean 使用的技术不同具体地说bad gmean 使用的是公有数据和一个公有方法该方法返回一个C-风格字符串。