C++异常与继承
<上一节
下一节>
在C++程序中,表示异常的类通常被组成为一个组(即如在前面各节讨论的那样)或者一个层次结构。
◆ 1、例如:定义一个称为Excp的基类,由它来打印错误信息:
class Excp
{
public:
void print(string msg)
{cerr<<msg<<endl;}
};
再从该基类派生出两个异常类:
class stackExcp:public Excp
{...}; //栈异常类的基类
class mathExcp:public Excp
{...}; //数学库异常的基类
进一步派生出其他异常类:
class popOnEmpty:public stackExcp
{...}; //栈空退栈异常
class pushOnFull:public stackExcp
{...}; //栈满压栈异常
class zeroOp:public mathExcp
{...}; //数学库零操作异常
class divideByZero:public mathExcp
{...}; //数学库被零除异常
形成了三层结构。
◆ 2、层次结构异常的抛出
以下做法是错的:
if(full())
{
pushOnFull except(data);
stackExcp *pse=&except; //pse指向的类对象为pushOnFull
throw *pse;
} //抛出的异常对象的类型为stackExcp
这里被创建的异常类对象是stackExcp类类型,尽管pse指向一个实际类型为pushOnFull的对象,但那是一个临时对象,复制到异常对象的存储区中时创建的却是stackExcp类的异常对象。所以该异常不能被pushOnFull类型的catch子句处理。
在处理类类型异常时,catch子句的排列顺序是非常重要的。
catch(pushOnFull){...} //处理pushOnFull异常
catch(stackExcp){...} //处理栈的其他异常
catch(Excp){...} //处理一般异常
派生类类型的catch子句必须先出现,以确保只有在没有其他catch子句适用时,才会进入基类类型的catch子句。
异常catch子句不必是与异常最匹配的catch子句,而是最先匹配到的catch子句,就是第一个遇到的可以处理该异常的catch子句。所以在catch子句列表中最特化的(匹配条件最严格的)catch子句必须先出现。
◆3、类层次结构下的异常重新抛出
类层次结构的异常同样可以重新抛出(rethrow),把一个异常传递给函数调用列表中更上层的另一个catch子句: throw;
重新抛出的异常仍是原来的异常对象。这个放在异常对象存储区中的异常的生命期应该是在处理该异常的一系列的子句中的最后一个退出时才结束,也就是直到异常解决了这时,才由异常类的析构函数来销毁它。这一系列的子句是由重新抛出联系起来的。
◆ 4、虚函数是类层次结构中多态性的基本手段,异常类层次结构中也可以定义虚拟函数。
【例10.2】异常层次结构中的虚函数。为调用派生类对象的虚函数,异常声明必须为一个指针或引用。 (查看源码)
◆ 1、例如:定义一个称为Excp的基类,由它来打印错误信息:
class Excp
{
public:
void print(string msg)
{cerr<<msg<<endl;}
};
再从该基类派生出两个异常类:
class stackExcp:public Excp
{...}; //栈异常类的基类
class mathExcp:public Excp
{...}; //数学库异常的基类
进一步派生出其他异常类:
class popOnEmpty:public stackExcp
{...}; //栈空退栈异常
class pushOnFull:public stackExcp
{...}; //栈满压栈异常
class zeroOp:public mathExcp
{...}; //数学库零操作异常
class divideByZero:public mathExcp
{...}; //数学库被零除异常
形成了三层结构。
◆ 2、层次结构异常的抛出
以下做法是错的:
if(full())
{
pushOnFull except(data);
stackExcp *pse=&except; //pse指向的类对象为pushOnFull
throw *pse;
} //抛出的异常对象的类型为stackExcp
这里被创建的异常类对象是stackExcp类类型,尽管pse指向一个实际类型为pushOnFull的对象,但那是一个临时对象,复制到异常对象的存储区中时创建的却是stackExcp类的异常对象。所以该异常不能被pushOnFull类型的catch子句处理。
在处理类类型异常时,catch子句的排列顺序是非常重要的。
catch(pushOnFull){...} //处理pushOnFull异常
catch(stackExcp){...} //处理栈的其他异常
catch(Excp){...} //处理一般异常
派生类类型的catch子句必须先出现,以确保只有在没有其他catch子句适用时,才会进入基类类型的catch子句。
异常catch子句不必是与异常最匹配的catch子句,而是最先匹配到的catch子句,就是第一个遇到的可以处理该异常的catch子句。所以在catch子句列表中最特化的(匹配条件最严格的)catch子句必须先出现。
◆3、类层次结构下的异常重新抛出
类层次结构的异常同样可以重新抛出(rethrow),把一个异常传递给函数调用列表中更上层的另一个catch子句: throw;
重新抛出的异常仍是原来的异常对象。这个放在异常对象存储区中的异常的生命期应该是在处理该异常的一系列的子句中的最后一个退出时才结束,也就是直到异常解决了这时,才由异常类的析构函数来销毁它。这一系列的子句是由重新抛出联系起来的。
◆ 4、虚函数是类层次结构中多态性的基本手段,异常类层次结构中也可以定义虚拟函数。
【例10.2】异常层次结构中的虚函数。为调用派生类对象的虚函数,异常声明必须为一个指针或引用。 (查看源码)
<上一节
下一节>