C++错误与异常处理
概念:
1.错误:分为编译时的错误和运行时的错误。
①编译时的错误:编译时的错误主要是语法错误,比如:句尾没有加分号,括号不匹配,关键字错误等,这类错误比较容易修改,因为编译系统会指出错误在第几行,什么错误。
② 运行时的错误: 运行时的错误则不容易修改,因为其中的错误是不可预料的,或者可以预料但无法避免的,比如内存空间不够,或者在调用函数时,出现数组越界等错误。
如果对于这些错误没有采取有效的防范措施,那么往往会得不到正确的运行结果,程序不正常终止或严重的会出现死机现象。我们把程序运行时的错误统称为异常,对异常处理称为异常处理。C++中所提供的异常处理机制结构清晰,在一定程度上可以保证程序的健壮性。
异常处理:
C++中处理异常的过程是这样的:在执行程序发生异常,可以不在本函数中处理,而是抛出一个错误信息,把它传递给上一级的函数来解决,上一级解决不了,再传给其上一级,由其上一级处理。如此逐级上传,直到最高一级还无法处理的话,运行系统会自动调用系统函数terminate,由它调用abort终止程序。这样的异常处理方法使得异常引发和处理机制分离,而不在同一个函数中处理。这使得底层函数只需要解决实际的任务,而不必过多考虑对异常的处理,而把异常处理的任务交给上一层函数去处理。
C++的异常处理机制有3部分组成:try(检查),throw(抛出),catch(捕获)。把需要检查的语句放在try模块中,检查语句发生错误,throw抛出异常,发出错误信息,由catch来捕获异常信息,并加以处理。一般throw抛出的异常要和catch所捕获的异常类型所匹配。异常处理的一般格式为:
try
{
被检查语句
throw 异常
}
catch(异常类型1)
{
进行异常处理的语句1
}
catch(异常类型2)
{
进行异常处理的语句2
}
...
直接上代码吧:
①
# if 1
# include <iostream>
using namespace std;
void f(int n)
{
cout<<"进入函数g,n = "<<n<<endl;
try
{
if(n == 1)
{
throw 1;//抛出Int类型异常
}
if(n == 2)
{
throw 2.1;//抛出double类型异常
}
if(n == 3)
{
throw "abc";//抛出字符串类型异常
}
}
catch(char *)
{
cout<<"捕获字符串类型的异常!"<<endl;
}
cout<<"退出函数f,n = "<<n<<endl;
}
void g(int n)
{
cout<<"进入函数g,n = "<<n<<endl;
try
{
f(n);
}
catch(double)
{
cout<<"捕获double类型的异常!"<<endl;
}
cout<<"退出函数g,n = "<<n<<endl;
}
int main()
{
for(int i = 3; i > 0; i--)
{
try
{
g(i);
}
catch(int)
{
cout<<"捕获int类型的异常!"<<endl;
}
cout<<endl;
}
return 0;
}
/*
<pre name="code" class="cpp">(vs 2012)<span style="font-family: Arial, Helvetica, sans-serif;">运行结果:</span>
进入函数g,n = 3
进入函数g,n = 3
捕获字符串类型的异常!
退出函数f,n = 3
退出函数g,n = 3
进入函数g,n = 2
进入函数g,n = 2
捕获double类型的异常!
退出函数g,n = 2
进入函数g,n = 1
进入函数g,n = 1
捕获int类型的异常!
请按任意键继续. . .
*/
# endif
②
# if 1
# include <iostream>
using namespace std;
void fun1(bool flag)
{
if(flag)
{
throw 1;
}
}
void fun2(bool flag)
{
if(flag)
{
throw 'c';
}
}
void fun3(bool flag)
{
if(flag)
{
throw "abc";
}
}
class CMyExcept{
public:
void display()
{
cout<<"自定义异常类"<<endl;
}
};
void fun4(bool flag)
{
if(flag)
{
throw CMyExcept();
}
}
void usage()
{
const char* str ="1 抛出整数类型异常\n2 抛出字符类型异常\n3 抛出字符串类型异常\n4 抛出自定义类型异常\n0 退出循环\n";
cout<<str<<endl;
}
int main()
{
usage();
bool flag = false;
while(!flag)
{
int select;
cin>>select;
try
{
if(0 == select)
{
flag = true;
}
fun1(select == 1);
fun2(select == 2);
fun3(select == 3);
fun4(select == 4);
}
catch(int i)
{
cout<<"捕获到整数类型异常,根据为: ";
cout<<i<<endl;
}
catch(char c)
{
cout<<"捕获到字符类型异常,根据为: ";
cout<<c<<endl;
}
catch(char *str)
{
cout<<"捕获到字符串类型异常,根据为: ";
cout<<str<<endl;
}
catch(CMyExcept &e)
{
cout<<"捕获到自定义类型异常,根据为: ";
e.display();
}
}
return 0;
}
/*
(vs 2012)运行结果:
1 抛出整数类型异常
2 抛出字符类型异常
3 抛出字符串类型异常
4 抛出自定义类型异常
0 退出循环
1
捕获到整数类型异常,根据为: 1
2
捕获到字符类型异常,根据为: c
3
捕获到字符串类型异常,根据为: abc
4
捕获到自定义类型异常,根据为: 自定义异常类
0
请按任意键继续. . .
*/
# endif
补充:1.try 和 catch的花括号{}不能省略。
2.一个try可以和多个catch进行匹配,以便满足不同类型异常的处理。
3.catch(...){} 可以捕获任意类型的异常。
4.如果throw内无任何语句,表示它将异常重新抛出原来的异常,交由上一层的catch进行处理。