14-将对象用作异常类型
15.3.4 将对象用作异常类型
通常,引发异常的函数将传递一个对象。这样做的重要优点之一是,可以使用不同的异常类型来区分不同的函数在不同情况下引发的异常。另外,对象可以携带信息,程序员可以根据这些信息来确定引发异常的原因。同时,catch块可以根据这些信息来决定采取什么样的措施。例如,下面是针对函数hmean()引发的异常而提供的一种设计:
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()
{
std::cout << "hmean(" << v1 << ", " << v2 <<"): "
<< "invalid arguments: a = -b\n";
}
可以将一个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
catch (bad_hmean & bg) // start of catch block
{
...
}
catch (bad_gmean & hg)
{
...
} // end of catch block
如果函数hmean()引发bad_hmean异常,第一个catch块将捕获该异常;如果gmean()引发bad_gmean异常,异常将逃过第一个catch块,被第二个catch块捕获。
程序清单15.10 exc_mean.h
// exc_mean.h -- exception classes for hmean(), gmean()
#include <iostream>
class 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.11 error4.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 block
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 <q to quit>: ";
}// end of try block
catch (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 don't get to play any more.\n";
break;
} // end of catch block
}
cout << "Bye!\n";
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()函数输入导致程序终止:
Enter two numbers: 4 12
Harmonic mean of 4 and 12 is 6
Geometric mean of 4 and 12 is 6.9282
Enter next set of numbers <q to quit>: 5 -5
hmean(5, -5): invalid arguments: a = -b
Try again.
5 -2
Harmonic mean of 5 and -2 is -6.66667
gmean() arguments should be >= 0
Values used: 5, -2
Sorry, you don't get to play any more.
Bye!
首先,bad_hmean异常处理程序使用了一条continue语句,而bad_gmean异常处理程序使用了一条break语句。因此,如果用户给函数hmean()提供的参数不正确,将导致程序跳过循环中余下的代码,进入下一次循环;而用户给函数gmean()提供的参数不正确时将结束循环。这演示了程序如何确定引发的异常(根据异常类型)并据此采取相应的措施。
其次,异常类bad_gmean和bad_hmean使用的技术不同,具体地说,bad_gmean使用的是公有数据和一个公有方法,该方法返回一个C-风格字符串。