1. 异常
异常:发生错误
C++是一种容错机制,允许主动发生错误、主动捕获错误、主动去处理错误。
1.1 处理流程:
(1)主动产生异常,抛出异常
(2)检测是否产生了异常
(3)捕获异常并对该异常进行处理
1.1.1 throw关键字
用于抛出异常,即主动产生异常
使用格式:
throw 异常的类型 ; //抛出该种类型的异常
1.1.2 try代码块
用于检测是否产生异常
使用格式:
try
{
//待检测的代码
}
1.1.3 catch代码块
用于捕获异常并处理异常
使用格式:
catch(捕获的异常类型) //直接放置类型
{
//对异常进行处理
}
1.2 举例
except.cpp
#include "iostream"
using namespace std;
//模拟捕获处理异常
int get_Value(int a, int b)//获取a/b的值,会出现b等于0的情况
{
if (b == 0)//分母不能为零,为零则抛出异常
{
throw 1; //throw后面写具体的数据
}
return a / b;
}
int main()
{
try//用于检测是否产生异常
{
get_Value(10, 0);
}
catch (int)//捕获并处理异常
{
//处理该异常
cout << "产生的异常:分母为0" << endl;
}
catch (char)//因为我们抛出的使整型异常,这个是捕获字符异常,所以捕获不到
{
}
cout << "检测完成" << endl;
return 0;
}
1.3 练习
except_test.cpp
#include <iostream>
#include <cmath>
#include <stdexcept>
using namespace std;
/*
设计一个直线类line (直线的方程为ax+by+c=0),其中直线包含了三个数据成员a,b,c
(1)包含一 个显示数据成员的方法: display()
(2)包含一个求两直线交点的友元函数setpoint,该友元函数里要求当两直线平行或交点坐标(x和y) 的绝对值大于等于10^8时,可抛出异常信息,给予用户提示
直线1:
ax+by+c=0;
直线2:
Ax+By+C=0;
交点坐标
x= (bC-Bc) / (Ba-Ab)
y= (aC-Ac) / (Ab-Ba)
*/
class Line {
private:
double a, b, c; // 直线方程的系数
public:
//构造函数
Line(double a_val, double b_val, double c_val) : a(a_val), b(b_val), c(c_val) {//给属性赋值
}
// 显示数据成员的方法
void display() const {
cout << "直线方程:" << a << "x + " << b << "y + " << c << " = 0" << endl;
}
// 友元函数求两直线交点
friend void setPoint(const Line& line1, const Line& line2);
};
// 计算两直线交点的函数---友元函数
void setPoint(const Line& line1, const Line& line2) {
// 判断两直线是否平行
if ((line1.a * line2.b - line2.a * line1.b) == 0) {
throw runtime_error("两直线平行,无交点!");
}
// 计算交点坐标
double x = (line1.b * line2.c - line2.b * line1.c) / (line1.a * line2.b - line2.a * line1.b);
double y = (line1.a * line2.c - line2.a * line1.c) / (line2.a * line1.b - line1.a * line2.b);
// 判断交点坐标绝对值是否大于等于10^8
if (abs(x) >= 1e8 || abs(y) >= 1e8) { //1e8 表示为 1 乘以 10 的 8 次方 abs(x)求绝对值
throw runtime_error("交点坐标过大,请重新输入合适的直线参数!");
}
// 输出交点坐标
cout << "两直线交点坐标为: (" << x << ", " << y << ")" << endl;
}
int main() {
//定义两条直线
Line line1(2, 3, 4); // 示例直线1: 2x + 3y + 4 = 0
Line line2(4, 6, 8); // 示例直线2: 4x + 6y + 8 = 0
//打印两条直线
line1.display();
line2.display();
//捕获处理异常
try {
setPoint(line1, line2);
}
catch (const runtime_error& e) {//用于表示在运行时检测到的错误
cout << "Error: " << e.what() << endl; //e.what()是用于获取异常对象e中存储的错误消息的方法
}
return 0;
}
1.4 异常捕获的嵌套
1.4.1 注意事项:
(1)try代码块后面需要紧跟着至少一个catch块,try与catch是同时出现的
(2)try代码块后的catch块的捕获顺序是按照catch的先后顺序进行捕获
(3)try检测出有异常发生,但未用catch块对异常进行捕获,那么该异常会被往try...catch块的上一级进行捕获,如果上一级也没有捕获到,继续往上抛,直到main函数种都没有捕获该异常,那么会调用windows的terminate来终止应用程序
(4)try...catch块可以允许嵌套,首先是内层的try..catch捕获异常,内层没有捕获到,外层的try..catch捕获异常,以此类推直到main函数种都没有捕获该异常,那么会调用windows的terminate来终止应用程序
格式:
try
{
try
{
...
}
catch()
{
}
....
}
catch()
{
}
....
1.4.2 举例
buhuo_except.cpp
#include <iostream>
using namespace std;
//异常捕获的嵌套使用
void function() {
throw "异常扔出";
}
int main() {
try {
// 外层异常处理块
try {
function();
}
catch (const char*) {
//throw; // 可以在这里处理内层异常,也可以选择继续抛出,如果抛出则内部不捕获,外部获得捕获
cout << "内层捕获字符串类型的异常" << endl;
}
}
catch (const char*) {
cout << "外层捕获字符串类型的异常" << endl;
}
return 0;
}
1.5 捕获所有异常
.... 代表捕获所有异常
捕获所有异常,将捕获所有异常的catch块放其它catch块的最后面
格式:
catch(...) //表示捕获所有异常
{
}
1.5.1 举例
buhuo_except.cpp
//捕获所有异常 使用 ...
void function() {
throw "异常扔出";
}
int main() {
try {
function();
}
catch (...) {
cout << "捕获所有异常" << endl;
}
return 0;
}
2. 标准异常
2.1 知识点
C++已经封装好的异常,只要用户产生了这些异常,编译器会自动抛出异常信息,封装好的异常类:exception(是所有标准异常的父类或基类)
如何查看产生了标准的异常:exception类中提供了what()方法
std::exception 该异常是所有标准 C++ 异常的父类。
std::bad_alloc 该异常可以通过 new 抛出。
std::bad_cast 该异常可以通过 dynamic_cast 抛出。
std::bad_exception 这在处理 C++ 程序中无法预期的异常时非常有用。
std::bad_typeid 该异常可以通过 typeid 抛出。
std::logic_error 理论上可以通过读取代码来检测到的异常。
std::domain_error 当使用了一个无效的数学域时,会抛出该异常。
std::invalid_argument 当使用了无效的参数时,会抛出该异常。
std::length_error 当创建了太长的 std::string 时,会抛出该异常。
std::out_of_range 参数超出有效范围
std::runtime_error 理论上不可以通过读取代码来检测到的异常。
std::overflow_error 当发生数学上溢时,会抛出该异常。
std::range_error 当尝试存储超出范围的值时,会抛出该异常。
std::underflow_error 当发生数学下溢时,会抛出该异常。
2.2 举例
buhuo_except.cpp
//标准异常
//演示越界标准异常
int main()
{
try
{
string a = "hello";
cout << "数据:" << a.at(1000) << endl;
}
catch (std::out_of_range& obj)//std::out_of_range,一般是应用于string或vector,at方法访问string或vector中的内容时会产生out_of_range
{
cout << "异常的类型:" << obj.what() << endl;
}
catch (std::exception& obj)
{
cout << "父类异常捕获到:" << obj.what() << endl;
}
return 0;
}
3. 自定义异常类
自定义异常类
需要继承异常的父类:exception,重写what方法
self_except.cpp
#include "iostream"
using namespace std;
//自定义异常类
class MyException :public exception//继承异常的父类
{
public:
MyException(const char* obj) //构造函数
{
this->error_string = new char[20];
strcpy_s(error_string, 20, obj);//给成员变量赋值
}
const char* what()const//重写what()函数,用于返回错误信息
{
return this->error_string;
}
//成员属性
char* error_string;
};
int main()
{
try
{
throw MyException("字符串异常!");//抛出自定义字符串异常
}
catch (MyException& obj)
{
cout << "异常的类型:" << obj.what() << endl;//obj.what()显示异常信息
}
cout << "hello world" << endl;
return 0;
}