C++的异常

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;
}

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值