• C++标准异常库


    一 标准异常类的成员:

    ① 在上述继承体系中,每个类都有提供了构造函数、复制构造函数、和赋值操作符重载。

    ② logic_error类及其子类、runtime_error类及其子类,它们的构造函数是接受一个string类型的形式参数,用于异常信息的描述

    ③ 所有的异常类都有一个what()方法,返回const char* 类型(C风格字符串)的值,描述异常信息。

    1.1 标准异常类的具体描述:

    异常名称

    描述

    exception

    所有标准异常类的父类

    bad_alloc

    当operator new and operator new[],请求分配内存失败时

    bad_exception

    这是个特殊的异常,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出了异常抛出列表中没有的异常,这是调用的unexpected函数中若抛出异常,不论什么类型,都会被替换为bad_exception类型

    bad_typeid

    使用typeid操作符,操作一个NULL指针,而该指针是带有虚函数的类,这时抛出bad_typeid异常

    bad_cast

    使用dynamic_cast转换引用失败的时候

    ios_base::failure

    io操作过程出现错误

    logic_error

    逻辑错误,可以在运行前检测的错误

    runtime_error

    运行时错误,仅在运行时才可以检测的错误

     1.2 logic_error的子类:

    异常名称

    描述

    length_error

    试图生成一个超出该类型最大长度的对象时,例如vector的resize操作

    domain_error

    参数的值域错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数

    out_of_range

    超出有效范围

    invalid_argument

    参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常

    1.3 runtime_error的子类:

    异常名称

    描述

    range_error

    计算结果超出了有意义的值域范围

    overflow_error

    算术计算上溢

    underflow_error

    算术计算下溢

    invalid_argument

    参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常

    示例代码:

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include <iostream>
    3. using namespace std;
    4. #include <stdexcept> // 标准异常
    5. class num_1
    6. {
    7. public:
    8. int age;
    9. num_1(int age)
    10. {
    11. if(age<0 || age>150)
    12. {
    13. throw length_error("年龄有错误");
    14. }
    15. }
    16. };
    17. int main(void)
    18. {
    19. try
    20. {
    21. num_1 p1(1112);
    22. }
    23. catch(exception &p2)
    24. {
    25. cout << "类型异常,异常类为:" << p2.what() << endl;
    26. }
    27. return 0;
    28. }

            在代码中,定义了一个类num_1,其中有一个构造函数,用于判断年龄是否符合要求,并抛出标准异常length_error。在主函数中,通过使用try-catch语句来捕获并处理异常。如果捕获到异常,会输出异常类的信息。通过这种方式可以处理并控制程序中的异常情况。

    二 自己写一个异常类

    2.1 为什么自己写异常类

    ① 标准库中的异常是有限的;

    ② 在自己的异常类中,可以添加自己的信息。(标准库中的异常类值允许设置一个用来描述异常的字符串)。

    2.2 如何编写自己的异常类?

    ① 建议自己的异常类要继承标准异常类。因为C++中可以抛出任何类型的异常,所以我们的异常类可以不继承自标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开发时。

    ② 当继承标准异常类时,应该重载父类的what函数。

    2.3 异常类的编写

    2.3.1 多态

            因为我们自己编写的异常类要继承自 exception 这个标准异常类,所以我们应该有一种思路就是使用多态来扩展,多态的好处就是不影响原基类的情况下进行安全扩展。

             我们来到 exception 类的定义:

    1. virtual const char*
    2. what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;

            可以看到标准异常类也为多态做好了准备,做了一个virtual的虚函数。注意这里返回的是char* 类型的数组。

    2.3.2 异常类的编写

            第一步先写一个继承类,继承自exception。

    代码如下:

    1. class num_1:public exception //自己写的异常类
    2. {
    3. private:
    4. string msg;
    5. public:
    6. num_1(string msg)
    7. {
    8. this->msg = msg;
    9. }
    10. virtual const char *what() // 记得这里的返回值是char*
    11. {
    12. return this->msg.c_str(); // .c_str()作用是类型转换,即string——>char*
    13. }
    14. };

            第二步做了一个普通的类,并在异常处使用 throw 抛出异常类 num_1。

    代码如下:

    1. class num_2 //普通类,进行年龄判断
    2. {
    3. public:
    4. int age;
    5. num_2(int age)
    6. {
    7. if(age<0 || age>160)
    8. {
    9. if(age<0)
    10. {
    11. throw num_1("年龄小于0,异常"); //抛异常
    12. }
    13. else
    14. {
    15. throw num_1("年龄大于160,异常"); //抛异常
    16. }
    17. }
    18. else
    19. {
    20. this->age = age;
    21. }
    22. }
    23. };

            第三步,在 main 函数中进行。

    代码如下:

    1. try
    2. {
    3. num_2 p1(180);
    4. }
    5. catch (exception &e) // 相当于exception &e = num_1("年龄大于160,异常") 符合多态条件
    6. {
    7. cout << e.what() << endl;
    8. }

     总体代码:

    1. #include <cmath>
    2. #include <cstdlib>
    3. #include <cstring>
    4. #include <ctime>
    5. #include <iostream>
    6. #include <string>
    7. #include<iomanip>
    8. #include<fstream> //头文件流
    9. #include<vector>
    10. using namespace std;
    11. class num_1:public exception //自己写的异常类
    12. {
    13. private:
    14. string msg;
    15. public:
    16. num_1(string msg)
    17. {
    18. this->msg = msg;
    19. }
    20. virtual const char *what() // 记得这里的返回值是char*
    21. {
    22. return this->msg.c_str(); // .c_str()作用是类型转换,即string——>char*
    23. }
    24. };
    25. class num_2
    26. {
    27. public:
    28. int age;
    29. num_2(int age)
    30. {
    31. if(age<0 || age>160)
    32. {
    33. if(age<0)
    34. {
    35. throw num_1("年龄小于0,异常");
    36. }
    37. else
    38. {
    39. throw num_1("年龄大于160,异常");
    40. }
    41. }
    42. else
    43. {
    44. this->age = age;
    45. }
    46. }
    47. };
    48. int main(void)
    49. {
    50. try
    51. {
    52. num_2 p1(180);
    53. }
    54. catch (num_1 &e) // exception &e = num_1("年龄大于160,异常")
    55. {
    56. cout << e.what() << endl;
    57. }
    58. return 0
    59. }

    总结

    • 异常类可以通过继承exception类来自定义
    • 异常类可以包含自定义的错误信息,方便在异常处理时输出错误原因
    • 异常类的成员函数what()必须被重写,返回错误信息的char*类型
    • 在异常类的构造函数中,可以通过条件判断来抛出异常,例如判断年龄是否小于0或大于160
    • 在主函数中,可以使用try-catch块来捕获并处理抛出的异常
    • 捕获到的异常对象可以通过引用传递给catch块,然后使用e.what()来输出错误信息

  • 相关阅读:
    12 克莱姆法则的几何解释
    java计算机毕业设计微留学学生管理系统源程序+mysql+系统+lw文档+远程调试
    Xsell中常用的Linux命令
    微服务系统设计——数据模型与系统架构设计
    tcpdump抓包实现过程
    Win10安装TensorRT
    《Hidden Markov Map Matching Through Noise and Sparseness》读书笔记
    Ansible自动化运维
    【408数据结构与算法】—栈的抽象数据类型定义(十)
    (ICONIP2021)On the Unreasonable Effectiveness of Centroids in Image
  • 原文地址:https://blog.csdn.net/weixin_47378530/article/details/139810989