bad_alloc : public exception
{
public:
bad_alloc() throw();
bad_alloc(const bad_alloc &) throw();
bad_alloc &operator=(const bad_alloc &) throw();
virtual ~bad_alloc() throw();
//异常说明符放在const限定符之后
virtual const char *what() const throw();
};
5、异常说明与析构函数
isbn_mismatch类将析构函数定义为:
class isbn_mismatch : public std::logic_error
{
public:
virtual ~isbn_mismatch() throw()
{
}
};
isbn_mismatch类从logic_error类继承而来,logic_error是一个标准异常类,该标准异常类的析构函数包含空throw(),它们承诺不抛出任何异常。当继承这两个类中的一个时,我们的析构函数也必须承诺不抛出任何异常。
class isbn_mismatch : public std::logic_error
{
public:
virtual ~isbn_mismatch(); //Error
};
out_of_stock类没有成员,所以它的合成析构函数不做任何可能抛出异常的事情,因此,编译器可以知道合成析构函数将遵守不抛出异常的承诺。
isbn_mismatch类有两个string类成员,这意味着isbn_mismatch的合成析构函数调用 string析构函数。C++标准保证,string析构函数像任意其他标准库类析构函数一样,不抛出异常。但是,标准库的析构函数没有定义异常说明,在这种情况下,我们知道,但编译器不知道,string析构函数将不抛出异常。我们必须定义自己的析构函数来恢复析构函数不抛出异常的承诺。
6、异常说明与虚函数
基类中虚函数的异常说明,可以与派生类中对应虚函数的异常说明符不同。
但是,派生类虚函数的异常说明必须与对应基类虚函数的异常说明同样严格,或者比后者更受限。
这个限制保证,当使用指向基类类型的指针调用派生类虚函数的时候,派生类的异常说明不会增加新的可抛出异常:
class Base
{
public:
virtual double f1(double) throw();
virtual int f2(int) throw (std::logic_error);
virtual std::string f3() throw (std::logic_error,std::runtime_error);
};
class Derived : public Base
{
public:
//派生类不能在异常说明符列表中增加异常
double f1(double) throw (std::underflow_error); //Error
int f2(int) throw (std::logic_error); //OK
std::string f3() throw (); //OK
};
如果通过基类指针或引用进行函数调用,那么,这些类的用户所涉及的应该只是在基类中指定的异常。 通过派生类抛出的异常限制为由基类所列出的那些,在编写代码时就可以知道必须处理哪些异常。代码可以依赖于这样一个事实:基类中的异常列表是虚函数的派生类版本可以抛出的异常列表的超集。例如,当调用f3的时候,我们知道只需要处理logic_error或 runtime_error:
void compute(Base *pd) throw()
{
try
{
pd -> f3();
}
catch (const logic_error &le)
{
//...
}
catch (const runtime_error &re)
{
//...
}
}
在确定可能需要捕获什么异常的时候,compute函数使用基类中的异常说明。
十一、函数指针的异常说明
异常说明是函数类型的一部分。这样,也可以在函数指针的定义中提供异常说明:
void (*pf)(int) throw(runtime_error); //该函数只能抛出runtime_error异常
如果不提供异常说明,该指针就可以指向能够抛出任意类型异常的具有匹配类型的函数。
在用另一指针初始化带异常说明的函数的指针,或者将后者赋值给函数地址的时候,两个指针的异常说明不必相同,但是,源指针的异常说明必须至少与目标指针的一样严格。
void recoup(int) throw (runtime_error);
void (*pf1)(int) throw(runtime_error) = recoup; //OK
void (*pf2)(int) throw(runtime_error,logic_error) = recoup; //OK
//recoup函数抛出的异常类型超出了pf3所指定的,因此会引发一个编译错误
//但是:有些编译器在此并不报错,比如g++!
void (*pf3)(int) throw() = recoup; //Error
void (*pf4)(int) = recoup; //OK