异常
异常处理允许用户以一种有序的方式管理运行是出现的错误。使用C++的异常处理,用户程序在错误发生时可自动调用一个错误处理程序。异常处理最主要的优点是自动转向错误处理代码,而以前在大程序中这些代码是由“手工”编制的。
简单来说异常,是利用代码来代替程序员调试解决程序的出错
异常的优点
- 函数的返回值可以忽略,但异常不可忽略。如果程序出现异常,但是没有被捕获,程序就会终止,这多少会促使程序员开发出来的程序更加健壮。而如果没有使用C语言的error宏或者函数返回值,调试者都有可能忘记检查,从而没有对错误进行处理,结果造成程序莫名的终止或出现错误的结果。
- 整形返回值没有任何语义信息。而异常却包含语义信息,优势能从类名就能够体现出来。
- 整形返回值缺乏相关的上下文信息。异常作为一个雷,可以拥有自己的成员,这些成员就可以传递足够的信息。
- 异常处理可以在调用调剂。这是一个代码编写时的问题:假设在有多个函数的调用栈中出现了某个错误,使用整形返回码要求你再每一级函数中都要进行处理。而使用异常处理的栈展开机制,只需要在一出进行处理就可以了,不需要每级函数都处理。
基本语法
异常捕获是根据类型进行匹配的
int divide(int x,int y)
{
if(y==0)
{
throw y;
}
return x/y;
}
void test()
{
try//尝试捕获异常
{
divide(10,0);
}
catch(int e)//异常时根据类型进行匹配
{
cout<<"除数为"<<e<<"!"<<endl;
}
}
- 如果函数抛出异常,如果该函数没有处理异常,会抛到顶层函数,如果还没有会逐步抛出(跨函数),该层函数接下来的代码不会被执行。异常必须处理,而且是跨函数。
异常接口声明
- 为了加强程序的可读性,可以在函数声明中列出可能抛出异常的所有类型,例如:void func();throw(A,B,C);这个函数func能够且只能抛出类型A,B,C及其子类型的异常。
- 如果函数声明中没有包含异常接口声明,则此函数可以抛出任何类型的异常,例如void func()
- 一个不抛任何类型异常的函数可以声明为:void func() throw()
- 如果一个函数抛出了它的异常接口声明锁不允许抛出的异常,unexcepted函数会被调用,该函数默认行为调用terminate函数中断程序。
异常类型
可以定义捕获异常的类型:
//这个函数只能抛出int,float,char三种类型异常,抛出其他的就报错
void func() throw(int,float,char)
{
throw "abc";
}
//不能抛出任何异常
void func2() throw()
{
throw -1;
}
- 若没有任何类型,则不能抛出异常
- "…"代表,可以是任何异常
//......
catch(...)
{
cout<<"未知类型异常!"<<endl;
}
异常对象
//异常对象,使用方法与普通数据类型相似
class MyException
{
public:
MyException(char *str)
{
error = new char[strlen(str)+1];
strcpy(error,str);
}
void what()
{
cout<<"未知异常!"<<endl;
}
public:
char *error;
};
//抛出一个对象
void fun3()
{
throw MyException();
}
异常对象声明周期
- 普通元素异常对象catch处理完之后析构,catch()如果接的是引用,不用调用拷贝构造,catch处理完之后析构
- 指针的话在catch之前对象会析构掉,解决方法是throw new Exception,在catch里面delete
标准异常库
编写自己的异常类的规则:#include
- 自己的异常类要继承标准异常类。
- 重载父类的what函数和虚析构函数。
- 为什么要编写自己的异常类?
- 标准库中的异常时有限的
- 在自己的异常类中,可以添加自己的信息。(标准库中的异常类值允许设置一个用来描述异常的字符串)
- 如何编写自己的异常类?
- 建议自己的异常类要继承标准异常类。因为c++中可以抛出任何类型的异常,所以我们的异常类可以不继承标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开发时。
- 当继承标准异常类时,应该重载父类的what函数和虚析构函数
- 因为栈展开的过程中,要复制异常类型,那么要根据你再类中添加的成员考虑是否提供自己的复制构造函数。
class MyOutOfRange : public exception
{
public:
MyOutOfRange(char *error)
{
pError = new char[strlen(error)+1];
strcpy(pError,error);
}
~MyOutOfRange()
{
if(pError != NULL)
{
delete[] pError;
}
}
virtual const char *what() const
{
return pError;
}
public:
char *pError;
};