一、前言
程序运行时会出现不可预判错误:除数为 0、文件打开失败、数组越界、空指针访问。传统 if 判断只能简单拦截,异常机制可以统一捕获、分层处理运行时错误,避免程序直接崩溃。本篇讲解throw抛出异常、try-catch捕获、自定义异常类实战。
二、异常基础三要素
throw:主动抛出异常,触发错误信号try:包裹可能出错的代码块,监控异常catch:匹配对应类型异常,编写错误修复逻辑
基础语法模板
cpp
运行
try
{
// 风险代码,可能抛出异常
throw 异常数据;
}
catch(异常类型1 接收变量)
{
// 处理类型1错误
}
catch(异常类型2 接收变量)
{
// 处理类型2错误
}
三、基础案例:除数为 0 异常捕获
cpp
运行
#include <iostream>
using namespace std;
double calcDiv(int a, int b)
{
if(b == 0)
{
// 抛出字符串异常
throw "除数不能为0,运算非法";
}
return (double)a / b;
}
int main()
{
int x, y;
cout << "输入被除数、除数:";
cin >> x >> y;
try
{
double res = calcDiv(x, y);
cout << "计算结果:" << res << endl;
}
catch(const char *errMsg)
{
// 捕获抛出的字符串异常
cout << "运行错误:" << errMsg << endl;
}
return 0;
}
运行输入10 0,不会直接闪退,而是输出自定义错误提示。
四、多类型异常分层捕获
一段 try 代码可抛出不同类型异常,多个 catch 从上到下依次匹配:
cpp
运行
void test(int num)
{
if(num < 0)
throw num; // int类型异常
else if(num > 100)
throw "数值超出0~100范围"; // 字符串异常
else
throw 3.14; // double异常
}
int main()
{
int n;
cin >> n;
try
{
test(n);
}
catch(int e)
{
cout << "错误:负数 " << e << endl;
}
catch(const char *e)
{
cout << "错误提示:" << e << endl;
}
catch(double e)
{
cout << "浮点异常:" << e << endl;
}
return 0;
}
五、通用捕获 catch(...) 兜底所有异常
不确定抛出异常类型时,使用省略号捕获任意异常,必须放在所有 catch 最后:
cpp
运行
try
{
// 任意风险代码
}
catch(int e)
{
}
catch(...)
{
cout << "发生未知类型运行异常" << endl;
}
六、标准库内置异常类(std::exception)
C++ 标准库提供统一异常基类,包含文件、内存、范围、IO 错误,头文件<exception>:
常用子类:
runtime_error:运行时通用错误out_of_range:数组 / 字符串下标越界logic_error:逻辑参数错误bad_alloc:new 分配内存失败
标准异常使用示例
cpp
运行
#include <iostream>
#include <exception>
#include <string>
using namespace std;
void checkScore(int s)
{
if(s < 0 || s > 100)
{
throw out_of_range("分数必须在0~100之间");
}
}
int main()
{
int score;
cin >> score;
try
{
checkScore(score);
cout << "分数合法" << endl;
}
catch(const exception &e)
{
// what() 返回异常描述文本
cout << "异常:" << e.what() << endl;
}
return 0;
}
七、自定义异常类(大型项目规范写法)
继承std::exception重写what(),区分业务错误:
cpp
运行
#include <iostream>
#include <exception>
#include <string>
using namespace std;
// 自定义文件操作异常
class FileErr : public exception
{
public:
string msg;
FileErr(string s):msg(s){}
const char* what() const noexcept override
{
return msg.c_str();
}
};
void openFile()
{
bool openSuccess = false;
if(!openSuccess)
throw FileErr("目标txt文件不存在,打开失败");
}
int main()
{
try
{
openFile();
}
catch(const FileErr &e)
{
cout << "文件异常:" << e.what() << endl;
}
catch(const exception &e)
{
cout << "系统异常:" << e.what() << endl;
}
return 0;
}
八、异常传递与函数声明 throw
函数后可声明可能抛出的异常类型,规范接口:
cpp
运行
// 声明该函数只会抛出int、string异常
void func() throw(int, const char*);
若函数抛出未声明异常,程序直接终止。
九、新手避坑
catch 捕获类型必须和 throw 抛出类型严格匹配,否则匹配失败触发兜底
标准异常捕获必须用
const exception &引用,避免拷贝丢失信息异常未被任何 catch 捕获,程序直接调用
abort()强制退出析构函数禁止主动抛出异常,会造成内存资源泄漏
catch(...)只能捕获,无法获取异常详情,仅做兜底容错
十、综合实战:带异常校验的学生成绩录入系统
cpp
运行
#include <iostream>
#include <exception>
using namespace std;
void inputScore(int score)
{
if(score < 0)
throw runtime_error("分数不能为负数");
if(score > 100)
throw runtime_error("分数不能超过100");
cout << "录入成功,分数:" << score << endl;
}
int main()
{
int s;
cout << "输入考试分数:";
cin >> s;
try
{
inputScore(s);
}
catch(const runtime_error &err)
{
cout << "录入失败:" << err.what() << endl;
}
return 0;
}
十一、下期预告
下一篇:C++ STL 容器:vector 动态可变数组完整实战教程