【C++】异常处理 ⑦ ( 异常类的继承层次结构 | 抛出 / 捕获 多个类型异常对象 | 抛出子类异常对象 / 捕获并处理 父类异常对象 )

青旅半醒 2024-02-17 13:26 158阅读 0赞

文章目录

  • 一、抛出 / 捕获 多个类型异常对象
    • 1、抛出 / 捕获 多个类型异常对象
    • 2、操作弊端
    • 3、完整代码示例
  • 二、异常类的继承层次结构
    • 1、抛出子类异常对象 / 捕获并处理 父类异常对象
    • 2、完整代码示例 - 抛出子类异常对象 / 捕获并处理 父类异常对象

自定义的 异常类 , 可能存在 继承结构 ,

也就是说 在 同一个 try-catch 代码块中 , 如果需要 拦截 和 处理多个 异常时 ,

如果 这些异常都继承相同的父类 , 只需要拦截一个 父类异常即可 ,

本篇博客中 , 讨论 抛出 / 捕获 的 异常类 存在 继承结构 的情况 ;

一、抛出 / 捕获 多个类型异常对象


1、抛出 / 捕获 多个类型异常对象

定义一个函数 , 传入一个 int 类型的参数 , void fun(int a) , 判定传入的参数值大小 ;

只有参数为 60 的时候 , 符合要求 , 其它情况下 , 一律抛出异常 ,

  • 如果参数为负数 , 抛出 eNegative 异常 ;
  • 如果参数为 0 , 抛出 eZero 异常 ;
  • 如果参数 小于 60 , 抛出 eTooSmall 异常 ;
  • 如果参数 大于 60 , 抛出 eTooBig 异常 ;

首先 , 定义上述异常类 , 定义 4 个 自定义异常类 ;

  1. class eNegative {
  2. };
  3. class eZero {
  4. };
  5. class eTooBig {
  6. };
  7. class eTooSmall {
  8. };

然后 , 在函数中 , 根据不同的判断 , 抛出不同的异常 ,

  1. // 1. 在 函数 中 抛出异常
  2. void fun(int a) {
  3. // 判定数字大小, 只有 60 时是合法的
  4. // 只要传入的参数不是 60 就需要抛出不同的异常
  5. if (a == 60) {
  6. // 合法
  7. }
  8. else if (a < 0) {
  9. throw eNegative();
  10. }
  11. else if (a == 0) {
  12. throw eZero();
  13. }
  14. else if (a < 60) {
  15. throw eTooSmall();
  16. }
  17. else if (a > 60) {
  18. throw eTooBig();
  19. }
  20. }

最后 , 在 try-catch 代码块中 , 捕获异常 , 需要将 4 个异常 , 各自捕获一次 ;

  1. // 2. 捕获并处理异常
  2. try
  3. {
  4. // 调用可能产生异常的函数
  5. fun(0);
  6. }
  7. catch (eNegative& e) {
  8. cout << "参数是负数" << endl;
  9. }
  10. catch (eZero & e) {
  11. cout << "参数是 0" << endl;
  12. }
  13. catch (eTooSmall & e) {
  14. cout << "参数太小" << endl;
  15. }
  16. catch (eTooBig & e) {
  17. cout << "参数太大" << endl;
  18. }
  19. catch (...) {
  20. cout << "未知异常" << endl;
  21. }

2、操作弊端

上述操作 , 有一个弊端 , 那就是每次拦截处理异常时 , 都要手动编写多个 catch 分支 , 每个 catch 分支都要进行各自的操作 ;

如果要在多个位置 , 拦截处理异常 , 则需要编写的代码就太多了 ; 后期维护起来很复杂 ;

3、完整代码示例

代码示例 :

  1. #include "iostream"
  2. using namespace std;
  3. class eSize {
  4. };
  5. class eNegative {
  6. };
  7. class eZero {
  8. };
  9. class eTooBig {
  10. };
  11. class eTooSmall {
  12. };
  13. // 1. 在 函数 中 抛出异常
  14. void fun(int a) {
  15. // 判定数字大小, 只有 60 时是合法的
  16. // 只要传入的参数不是 60 就需要抛出不同的异常
  17. if (a == 60) {
  18. // 合法
  19. }
  20. else if (a < 0) {
  21. throw eNegative();
  22. }
  23. else if (a == 0) {
  24. throw eZero();
  25. }
  26. else if (a < 60) {
  27. throw eTooSmall();
  28. }
  29. else if (a > 60) {
  30. throw eTooBig();
  31. }
  32. }
  33. int main() {
  34. // 2. 捕获并处理异常
  35. try
  36. {
  37. // 调用可能产生异常的函数
  38. fun(0);
  39. }
  40. catch (eNegative& e) {
  41. cout << "参数是负数" << endl;
  42. }
  43. catch (eZero & e) {
  44. cout << "参数是 0" << endl;
  45. }
  46. catch (eTooSmall & e) {
  47. cout << "参数太小" << endl;
  48. }
  49. catch (eTooBig & e) {
  50. cout << "参数太大" << endl;
  51. }
  52. catch (...) {
  53. cout << "未知异常" << endl;
  54. }
  55. cout << "try-catch 代码块执行完毕" << endl;
  56. // 控制台暂停 , 按任意键继续向后执行
  57. system("pause");
  58. return 0;
  59. };

执行结果 :

参数是 0
try-catch 代码块执行完毕
请按任意键继续. . .

在这里插入图片描述

二、异常类的继承层次结构


1、抛出子类异常对象 / 捕获并处理 父类异常对象

如果 抛出 / 捕获 多个类型的异常对象 , 每次拦截处理异常时 , 都要手动编写多个 catch 分支 , 不利于代码维护 ;

如果将 相似类型的异常 都继承自 一个父类 , 那么每次拦截时 , 只需要拦截一个父类异常即可 ;

定义父类异常 , 其中定义一个纯虚函数 , 该纯虚函数是异常打印 , 或者异常处理的通用操作 ;

  1. class eSize {
  2. public:
  3. virtual void printError() = 0;
  4. };

剩余的 4 个异常类 , 都继承 异常类父类 , 并实现纯虚函数 ;

  1. class eNegative : public eSize {
  2. public:
  3. virtual void printError() {
  4. cout << "参数是负数" << endl;
  5. }
  6. };
  7. class eZero : public eSize {
  8. public:
  9. virtual void printError() {
  10. cout << "参数是 0" << endl;
  11. }
  12. };
  13. class eTooBig : public eSize {
  14. public:
  15. virtual void printError() {
  16. cout << "参数太大" << endl;
  17. }
  18. };
  19. class eTooSmall : public eSize {
  20. public:
  21. virtual void printError() {
  22. cout << "参数太小" << endl;
  23. }
  24. };

上述定义的纯虚函数 , 会发生多态 ;

在拦截父类对象时 , 调用不同的 异常对象 , 会分别调用不同子类的 虚函数方法 ;

抛出异常的函数如下 , 抛出异常时 , 需要抛出子类异常对象 ;

  1. // 1. 在 函数 中 抛出异常
  2. void fun(int a) {
  3. // 判定数字大小, 只有 60 时是合法的
  4. // 只要传入的参数不是 60 就需要抛出不同的异常
  5. if (a == 60) {
  6. // 合法
  7. }
  8. else if (a < 0) {
  9. throw eNegative();
  10. }
  11. else if (a == 0) {
  12. throw eZero();
  13. }
  14. else if (a < 60) {
  15. throw eTooSmall();
  16. }
  17. else if (a > 60) {
  18. throw eTooBig();
  19. }
  20. }

捕获并处理异常时 , 只需要拦截 父类异常对象即可 ;

  1. // 2. 捕获并处理异常
  2. try
  3. {
  4. // 调用可能产生异常的函数
  5. fun(0);
  6. }
  7. catch (eSize& e) {
  8. e.printError();
  9. }
  10. catch (...) {
  11. cout << "未知异常" << endl;
  12. }

2、完整代码示例 - 抛出子类异常对象 / 捕获并处理 父类异常对象

代码示例 :

  1. #include "iostream"
  2. using namespace std;
  3. class eSize {
  4. public:
  5. virtual void printError() = 0;
  6. };
  7. class eNegative : public eSize {
  8. public:
  9. virtual void printError() {
  10. cout << "参数是负数" << endl;
  11. }
  12. };
  13. class eZero : public eSize {
  14. public:
  15. virtual void printError() {
  16. cout << "参数是 0" << endl;
  17. }
  18. };
  19. class eTooBig : public eSize {
  20. public:
  21. virtual void printError() {
  22. cout << "参数太大" << endl;
  23. }
  24. };
  25. class eTooSmall : public eSize {
  26. public:
  27. virtual void printError() {
  28. cout << "参数太小" << endl;
  29. }
  30. };
  31. // 1. 在 函数 中 抛出异常
  32. void fun(int a) {
  33. // 判定数字大小, 只有 60 时是合法的
  34. // 只要传入的参数不是 60 就需要抛出不同的异常
  35. if (a == 60) {
  36. // 合法
  37. }
  38. else if (a < 0) {
  39. throw eNegative();
  40. }
  41. else if (a == 0) {
  42. throw eZero();
  43. }
  44. else if (a < 60) {
  45. throw eTooSmall();
  46. }
  47. else if (a > 60) {
  48. throw eTooBig();
  49. }
  50. }
  51. int main() {
  52. // 2. 捕获并处理异常
  53. try
  54. {
  55. // 调用可能产生异常的函数
  56. fun(0);
  57. }
  58. catch (eSize& e) {
  59. e.printError();
  60. }
  61. catch (...) {
  62. cout << "未知异常" << endl;
  63. }
  64. cout << "try-catch 代码块执行完毕" << endl;
  65. // 控制台暂停 , 按任意键继续向后执行
  66. system("pause");
  67. return 0;
  68. };

执行结果 :

参数是 0
try-catch 代码块执行完毕
请按任意键继续. . .

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,158人围观)

还没有评论,来说两句吧...

相关阅读