查看普通函数声明的时候,不可能确定该函数会抛出什么异常,但是,为了编写适当的catch子句,了解函数是否抛出异常以及会抛出那种异常是很有用的。异常说明(exception specification)指定,如果函数抛出异常,被抛出的异常将会是包含再说明中的一种,或者是从列出的异常派生的类型。
1、定义异常说明
异常说明跟在函数形参表之后。一个异常说明在关键字throw之后跟着一个(可能为空)由圆括号括住的异常类型列表:
void mayexcep(int) throw (runtime_error);
这个声明指出,mayexcep是接收int值的函数,并返回void。如果mayexcep抛出一个异常,该异常将是runtime_error对象,或者是由runtime_error派生的类型的异常。
空说明列表指出函数不抛出任何异常:
void no_problem() throw();
异常说明是函数接口的一部分,函数定义以及函数的任意声明必须具有相同的异常说明。
----------------如果一个函数声明没有指定异常类型,那么该函数可以抛出任意类型的异常---------------------------
2、违反异常声明
但是,不能在编译时知道程序是否抛出异常以及会抛出那些异常,只有在运行时才能检测是否违反了函数异常说明。
如果函数抛出了没有在其异常说明列中列出的异常,就会调用标准库函数unexpected。默认情况下,unexpected函数调用terminate函数,terminate函数一般会终止程序。
-----------------在编译的时候,编译器不能也不会试图验证异常说明-----------------------------------------------
3、确定函数不抛出异常
因为不能在编译时检查异常说明,异常说明的应用通常是有限的。
确定函数不会抛出任何异常,对函数的用户和编译器将是有所帮助的::知道函数不抛出异常会简化编写调用函数的异常安全代码的工作,我们可以知道在调用函数额时候不必担心异常,而且,如果编译器知道不会抛出异常,它就可以执行被可能抛出异常的代码所抑制的优化。
4、异常说明与类成员函数
就像非成员函数一样,成员函数声明的异常说明跟在函数形参表之后。例如,C++标准库中的bad_alloc类定义的所有成员都有空异常说明,这些成员承诺不抛出异常:
class 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();
virtual const char * whar() const throw();
}
注意,在const成员函数声明中,异常说明跟在const限定符之后。
5、异常说明与析构函数
class isbn_mismath:public std::logic_error{
public:
virtual ~isbn_mismatch() throw(){}
}
isbn_mismatch类从logic_error类继承而来,logic_error是一个标准异常类,该标准异常类的析构函数包含空throw()说明符,它们承诺不抛出任何异常。当继承这两个类的一个时,我们的析构函数也必须承诺不抛出任何异常。
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
}