导读:本期聚焦于小伙伴创作的《C++中函数异常与类异常的多重异常处理策略有哪些》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++中函数异常与类异常的多重异常处理策略有哪些》有用,将其分享出去将是对创作者最好的鼓励。

C++的异常处理机制允许程序在运行时检测并处理错误情况,函数异常通常指函数执行过程中抛出的基本类型异常,类异常则是通过自定义异常类抛出的结构化异常,两者在多重异常场景下需要配合合理的策略才能高效处理。

C++中函数异常与类异常的多重异常处理策略有哪些

函数异常与类异常的基础特性

函数异常

函数异常一般是函数内部直接抛出的内置类型或者字符串类型的异常,通常用来处理简单的错误场景。例如一个除法函数,当除数为0时抛出字符串异常:

#include <iostream>
#include <stdexcept>

// 除法函数,除数为0时抛出异常
double divide(double a, double b) {
    if (b == 0) {
        throw "除数不能为0"; // 抛出字符串类型的函数异常
    }
    return a / b;
}

int main() {
    try {
        double result = divide(10, 0);
        std::cout << "结果:" << result << std::endl;
    } catch (const char* err_msg) {
        std::cout << "捕获到函数异常:" << err_msg << std::endl;
    }
    return 0;
}

类异常

类异常是通过继承标准异常类或者自定义异常基类实现的异常类型,可以携带更多的错误信息,比如错误码、错误发生的位置等。通常会继承<stdexcept>中的<exception>基类,并重写what()方法返回错误描述:

#include <iostream>
#include <stdexcept>
#include <string>

// 自定义除零异常类
class DivideByZeroException : public std::exception {
private:
    std::string err_msg;
public:
    DivideByZeroException(const std::string& msg) : err_msg(msg) {}
    // 重写what方法返回错误描述
    const char* what() const noexcept override {
        return err_msg.c_str();
    }
};

double divide(double a, double b) {
    if (b == 0) {
        throw DivideByZeroException("自定义异常:除数不能为0"); // 抛出类异常
    }
    return a / b;
}

int main() {
    try {
        double result = divide(10, 0);
        std::cout << "结果:" << result << std::endl;
    } catch (const DivideByZeroException& e) {
        std::cout << "捕获到类异常:" << e.what() << std::endl;
    }
    return 0;
}

多重异常处理的核心策略

异常捕获的优先级顺序

当同时存在函数异常和类异常时,catch块的顺序非常关键,因为C++的异常捕获是按照顺序匹配的,子类异常必须放在父类异常之前。如果是自定义的类异常,需要先捕获具体的自定义异常类型,再捕获更通用的<std::exception>,最后捕获其他类型的函数异常:

#include <iostream>
#include <stdexcept>
#include <string>

class DivideByZeroException : public std::exception {
private:
    std::string err_msg;
public:
    DivideByZeroException(const std::string& msg) : err_msg(msg) {}
    const char* what() const noexcept override {
        return err_msg.c_str();
    }
};

double divide(double a, double b) {
    if (b == 0) {
        // 随机抛出两种类型的异常,模拟多重异常场景
        if (a > 5) {
            throw DivideByZeroException("除数为0的自定义类异常");
        } else {
            throw "除数为0的基础函数异常";
        }
    }
    return a / b;
}

int main() {
    double test_cases[2] = {10, 2};
    for (double b : test_cases) {
        try {
            double result = divide(10, b);
            std::cout << "计算结果:" << result << std::endl;
        } catch (const DivideByZeroException& e) { // 先捕获具体的自定义类异常
            std::cout << "捕获到自定义类异常:" << e.what() << std::endl;
        } catch (const std::exception& e) { // 再捕获标准异常基类
            std::cout << "捕获到标准异常:" << e.what() << std::endl;
        } catch (...) { // 最后用捕获所有类型的通用块兜底
            std::cout << "捕获到其他未知类型的函数异常" << std::endl;
        }
    }
    return 0;
}

异常的重新抛出策略

有时候捕获到异常后,当前函数无法完全处理,需要将异常传递给上层调用者处理,这时候可以使用重新抛出。重新抛出时不需要指定异常对象,直接使用throw;即可,并且会保留原始异常的类型和信息:

#include <iostream>
#include <stdexcept>
#include <string>

class DivideByZeroException : public std::exception {
private:
    std::string err_msg;
public:
    DivideByZeroException(const std::string& msg) : err_msg(msg) {}
    const char* what() const noexcept override {
        return err_msg.c_str();
    }
};

double divide(double a, double b) {
    if (b == 0) {
        throw DivideByZeroException("底层除数为0异常");
    }
    return a / b;
}

void process_divide(double a, double b) {
    try {
        double result = divide(a, b);
        std::cout << "处理模块计算结果:" << result << std::endl;
    } catch (const DivideByZeroException& e) {
        std::cout << "处理模块捕获到异常,准备重新抛出:" << e.what() << std::endl;
        throw; // 重新抛出异常,传递给上层
    }
}

int main() {
    try {
        process_divide(10, 0);
    } catch (const DivideByZeroException& e) {
        std::cout << "主函数最终捕获到异常:" << e.what() << std::endl;
    }
    return 0;
}

异常规范的使用建议

在早期C++标准中可以使用throw(异常类型列表)的语法声明函数可能抛出的异常,但C++11之后更推荐使用noexcept关键字标识函数是否抛出异常。如果函数不会抛出任何异常,可以添加noexcept修饰,帮助编译器做优化,也能让调用者明确异常边界:

#include <iostream>

// 该函数不会抛出异常,使用noexcept修饰
double safe_multiply(double a, double b) noexcept {
    return a * b;
}

// 该函数可能抛出异常,不添加noexcept
double divide(double a, double b) {
    if (b == 0) {
        throw "除数不能为0";
    }
    return a / b;
}

int main() {
    try {
        double r1 = safe_multiply(2, 3);
        std::cout << "乘法结果:" << r1 << std::endl;
        double r2 = divide(10, 0);
        std::cout << "除法结果:" << r2 << std::endl;
    } catch (const char* msg) {
        std::cout << "捕获到异常:" << msg << std::endl;
    }
    return 0;
}

多重异常处理的注意事项

  • 不要在析构函数中抛出异常,否则如果异常在析构时未被捕获,会导致程序直接终止
  • 自定义异常类尽量继承标准异常基类,保证异常体系的统一性
  • 避免在异常抛出频繁的场景中使用异常,异常处理的开销比普通条件判断更高
  • 捕获异常时尽量使用常引用,减少不必要的对象拷贝

合理的多重异常处理策略可以让程序的错误处理逻辑更清晰,减少未捕获异常导致的程序崩溃问题,开发者需要根据实际的业务场景选择合适的异常类型和捕获顺序,平衡代码的健壮性和可维护性。

C++异常函数异常类异常多重异常处理修改时间:2026-06-02 22:17:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。