概念
异常事件(如:除
0
溢出,数组下标越界,所要读取的文件不存在
,
空指针,内存不足
等等)
在
C
语言对错误的处理是两种方法:
一是使用整型的返回值标识错误;
二是使用 errno
宏(可以简单的理解为一个全局整型变量)去记录错误。
C++
异常不可忽略
(
如果忽略,进程结束
)
。
异常作为一个类,可以拥有自己的成员,这些成员就可以传递足够的信息。
抛出异常
---->
捕获异常。
示例:
int main(int argc, char *argv[])
{
int num = 10 / 0;
cout << "OVER" << endl;
return 0;
}
//不会显示OVER,程序异常结束
抛出异常
语法:throw 值或变量;
例如:
throw 0;
throw 1.1;
throw 'a';
throw "abc";
捕获异常
语法:
try{
可能会产生异常的代码
111
222 出现异常
333
}
catch(
数据类型
1
变量名
)
{
当throw
的值与数据类型
1
相同进入此处
}
catch(
数据类型
2
变量名
)
{
当throw
的值与数据类型
2
相同进入此处
}
...
catch(...)
{
当throw
的值以上数据类型都不相同进入此处
}
示例
#include <iostream>
#include <cstring>
using namespace std;
//异常步骤,抛出异常,捕获异常
int mydiv(int a,int b)
{
if(b == 0)
{
// 抛出异常
int num = 0;
throw num;
}
return a / b;
}
void test01(){
try{
mydiv(10,0);
}
catch(int e)
{
cout << e << endl;
}
catch(char const* s)
{
cout << s << endl;
}
catch(...)
{
cout << "其他异常" << endl;
}
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
栈解旋
概念
异常被抛出后,从进入 try
块起
,
到异常被抛掷前
,
这期间在栈上构造的所有对象
,
都会
被自动析构。析构的顺序与构造的顺序相反
,
这一过程称为栈的解旋
示例
class A{
private:
int num;
public:
A(int num):num(num)
{
cout << "构造函数" << num << endl;
}
~A()
{
cout << "析构函数" << num << endl;
}
};
void test02()
{
A a1(1);
A a2(2);
throw 0;
}
int main(int argc, char *argv[])
{
try{
test02();
}
catch(...)
{
}
return 0;
}
结果
构造函数1
构造函数2
析构函数2
析构函数1
异常的接口声明
作用
限定异常抛出的类型种类
语法
返回值类型 函数名(
形参列表
)throw(
数据类型
1,
数据类型
2,...)
{
函数体
}
注意:
声明异常后,当前函数中只能抛出指定类型的异常
throw():不允许抛出任何异常
示例
void fun01()throw(int,char)
{
// throw 10;//可以
// throw 'a';//可以
// throw 3.14f;//不可以
}
void test03(){
try{
fun01();
}
catch(int)
{
cout << "int的异常" << endl;
}
catch(char)
{
cout << "char的异常" << endl;
}
catch(float)
{
cout << "float的异常" << endl;
}
}
int main(int argc, char *argv[])
{
test03();
return 0;
}
异常对象的生命周期
示例1:抛出异常对象
#include <iostream>
#include <cstring>
using namespace std;
class B{
private:
int num;
public:
B(int num):num(num)
{
cout << "构造函数" << num << endl;
}
B(const B& b)
{
this->num = b.num;
cout << "拷贝构造" << num << endl;
}
~B()
{
cout << "析构函数" << num << endl;
}
};
void fun02()
{
throw B(10);
}
void test04()
{
try
{
fun02();
}
catch(B b)
{
}
}
int main(int argc, char *argv[])
{
test04();
cout << "OVER" << endl;
return 0;
}
结果
示例2:抛出异常对象指针
#include <iostream>
#include <cstring>
using namespace std;
class B{
private:
int num;
public:
B(int num):num(num)
{
cout << "构造函数" << num << endl;
}
B(const B& b)
{
this->num = b.num;
cout << "拷贝构造" << num << endl;
}
~B()
{
cout << "析构函数" << num << endl;
}
};
void fun02()
{
throw new B(10);
}
void test04()
{
try{
fun02();
}
catch(B *b)
{
}
}
int main(int argc, char *argv[])
{
test04();
cout << "OVER" << endl;
return 0;
}
结果:
示例3:抛出异常对象引用
#include <iostream>
#include <cstring>
using namespace std;
class B{
private:
int num;
public:
B(int num):num(num)
{
cout << "构造函数" << num << endl;
}
B(const B& b)
{
this->num = b.num;
cout << "拷贝构造" << num << endl;
}
~B()
{
cout << "析构函数" << num << endl;
}
};
void fun02()
{
throw B(10);
}
void test04()
{
try{
fun02();
}
catch(B &b)
{
}
}
int main(int argc, char *argv[])
{
test04();
cout << "OVER" << endl;
return 0;
}
结果:
异常的多态
概念
:
子类异常对象可以被父类异常类型捕获
示例1:
class BaseException{};
class MyException01:public BaseException{};
class MyException02:public BaseException{};
void test05()
{
try{
throw MyException01();
}
catch(BaseException)
{
cout << "可以捕获子类异常" << endl;
}
}
int main(int argc, char *argv[])
{
test05();
return 0;
}
示例
2:
子类异常重写父类虚函数
class BaseException{
public:
virtual void printMsg(){}
};
class NullException:public BaseException{
public:
virtual void printMsg(){
cout << "空指针异常" << endl;
}
};
class ArrOutException:public BaseException{
public:
virtual void printMsg(){
cout << "数组下标越界异常" << endl;
}
};
void test05()
{
try{
throw NullException();
}
catch(BaseException &e)
{
e.printMsg();
}
}
int main(int argc, char *argv[])
{
test05();
return 0;
}
标准异常库
简介
标准库中也提供了很多的异常类,它们是通过类继承组织起来的。异常类继承层级
.
结构图
所示
标准异常使用
void test06()
{
try{
throw bad_alloc();
}
catch(exception &e)
{
cout << e.what() << endl;
}
}
int main(int argc, char *argv[])
{
test06();
return 0;
}
自定义异常
步骤
1,定义一个类
2,继承与异常类
3,重写
wait
方法
示例
class my_exception:public exception
{
private:
char* msg;
public:
my_exception()
{
}
my_exception(char* msg)
{
this->msg = msg;
}
const char *what()const noexcept
{
return msg;
}
};
void test07()
{
try{
throw my_exception("自定义异常");
}
catch(exception &e){
cout << e.what() << endl;
}
}
int main(int argc, char *argv[])
{
test07();
return 0;
}