首页 > 编程语言 > 详细

C++中的异常处理(下)

时间:2019-05-24 19:56:28      阅读:139      评论:0      收藏:0      [点我收藏+]

1,catch 语句块中可以抛出异常:

    1,示意图:

技术分享图片 

    2,func() 在 try 语句块中,说明它有可能抛出异常,抛出的异常有可能是整型或其它类型;

    3,catch 语句块处理方式是将异常重新抛出去,其它什么也不干;

    4,此时需要外层的其它 try ... catch 语句块处理;

    5,catch() 中的参数类似于函数里面的参数,当 try() 里面抛出的异常在逐个匹配时,匹配上了以后异常元素就用来初始化 catch() 中的形参变量,因此 catch() 中的参数才会代表扔出来的异常,其实类似于函数调用过程有一个初始化的工作;

    6,函数调用里面实参和形参有可能进行类型转换,但是在 try ... catch 异常语句中绝对不会有任何的类型转换,严格匹配, 然后初始化;

    7,接受异常是任意类型时,只能通过 throw 扔出异常;

   

2,为什么要在 catch 中重新抛出异常?

 

3,catch 中捕获的异常可以被重新解释后抛出,工程中使用这样的统一异常类型:

    1,示意图:

 技术分享图片

    2,工程开发中使用 catch 中可以再次扔出异常的特性来重新解释一个异常;

    3,工程开发中一般会基于已有的库来进行,比如 STL 标准库,也有可能是我们自己的私有库;

    4,当我们发现私有库中有一些功能没有,但需要的功能在第三方库中是有的,所以我们要进行一层封装;

    5,在私有库中定义一个 MyFunc(int i) 函数,这个函数用来直接调用第三方库中的 func() 函数;

    6,进行封装的原因是 func() 函数的异常类型为 int 类型,比较简单,然而在私有库中我们定义了自己的异常类型为 Exception, 我们不想使用 int 类型,我们想要统一异常的类型,于是我们就在私有库中的 MyFunc() 函数中去捕获第三方库中 func() 函数抛出的异常,然后根据捕获的异常重新解释为我们想要的异常,这样我们工程开发中所面对的异常类型就是一致的;

    7,这就是工程中利用 catch 中可以重新抛出异常的特性来统一异常的类型;

   

4,异常的重新解释编程实验:

  1 #include <iostream>
  2 #include <string>
  3 
  4 using namespace std;
  5 
  6 void Demo()
  7 {
  8     try
  9     {
 10         try
 11         {
 12             throw c;
 13         }
 14         catch(int i)
 15         {
 16             cout << "Inner: catch(int i)" << endl;
 17             throw i;
 18         }
 19         catch(...)
 20         {
 21             cout << "Inner: catch(...)" << endl;
 22             throw;
 23         }
 24     }
 25     catch(...)
 26     {
 27         cout << "Outer: catch(...)" << endl;
 28     }
 29 }
 30 
 31 /*
 32     假设: 当前的函数是第三方库中的函数,因此,我们无法修改源代码
 33     
 34     函数名: void func(int i)
 35     抛出异常的类型: int
 36                         -1 ==》 参数异常
 37                         -2 ==》 运行异常
 38                         -3 ==》 超时异常
 39 */
 40 
 41 /* 第三方库函数,编写好后不能修改,因为我们一般没有源代码,这里仅是用于模拟 */
 42 void func(int i)
 43 {
 44     if( i < 0 )
 45     {
 46         throw -1;
 47     }
 48     
 49     if( i > 100 )
 50     {
 51         throw -2;
 52     }
 53     
 54     if( i == 11 )
 55     {
 56         throw -3;
 57     }
 58     
 59     cout << "Run func..." << endl;  // 没有异常,则执行 func() 函数功能;
 60 }
 61 
 62 /* 不能修改 func() 函数,则我们定义 MyFunc() 函数重解释 func() 的异常 */
 63 void MyFunc(int i)
 64 {
 65     try
 66     {
 67         func(i);  // 直接通过第三方库中的 func() 来实现我们需要的功能;
 68     }
 69     catch(int i)
 70     {
 71         switch(i)
 72         {
 73             case -1:
 74                 throw "Invalid Parameter";
 75                 break;
 76             case -2:
 77                 throw "Runtime Exception";
 78                 break;
 79             case -3:
 80                 throw "Timeout Exception";
 81                 break;
 82         }
 83     }
 84 }
 85 
 86 int main(int argc, char *argv[])
 87 {
 88     // Demo();
 89     
 90     try
 91     {
 92         MyFunc(11);  // 如果在这里调用 func(11),则下面 catch 语句块中会打印:Exception Info: -3; 这样就不能立刻反应出来出了什么事儿,此时要去找 func() 中的文档说明,这样的开发是非常痛苦的;
 93     }
 94     catch(const char* cs)
 95     {
 96         cout << "Exception Info: " << cs << endl;  // 打印:Exception Info: Timeout Exception
 97     }
 98     
 99     return 0;
100 }

    1,本例展示了工程中利用 catch 中可以重新抛出异常的特性来统一异常的类型;

    2,解释异常,重新抛出新的意义更加丰富的异常,字符串是不够的,可以定义自己的异常类类型,

   

5,异常的操作特性:

    1,异常的类型可以是自定义类类型;

    2,对于类类型异常的匹配依旧是自上而下严格匹配;

       1,只有赋值兼容性是意外;

    3,赋值兼容性原则在异常匹配中依然适用;

       1,子类的异常对象可以被父类的 catch 语句块抓住;

    4,一般而言(这里是将异常类型编程自定义的类类型应该遵守的原则):

       1,匹配子类异常的 catch 放在下部;

       2,匹配父类异常的 catch 放在上部;

      

6,工程中异常类的特性:

    1,在工程中会定义一系列的异常类;

       1,这些类是一个类族,有很严格的继承层次结构;

    2,每个类代表工程中可能出现的一种异常类型;

    3,代码复用时可能需要重解释不同的异常类;

       1,刚才展示的 catch 的特性;

    4,在定义 catch 语句块时推荐使用引用作为参数;

       1,catch 语句块要捕获的异常是类对象异常的时候,推荐使用引用作为参数,避免拷贝构造,提高程序效率;

   

7,类型的异常编程实验:

  1 #include <iostream>
  2 #include <string>
  3 
  4 using namespace std;
  5 
  6 class Base
  7 {
  8 };
  9 
 10 /* 定义异常类 */
 11 class Exception : public Base
 12 {
 13     int m_id;
 14     string m_desc;
 15 public:
 16     Exception(int id, string desc)
 17     {
 18         m_id = id;
 19         m_desc = desc;
 20     }
 21     
 22     int id() const
 23     {
 24         return m_id;
 25     }
 26     
 27     string description() const
 28     {
 29         return m_desc;
 30     }
 31 };
 32 
 33 /*
 34     假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码
 35     函数名: void func(int i)
 36     抛出异常的类型: int
 37                         -1 ==》 参数异常
 38                         -2 ==》 运行异常
 39                         -3 ==》 超时异常
 40 */
 41 
 42 /* 第三方库函数,编写好后不能修改,因为我们一般没有源代码,这里仅是用于模拟 */
 43 void func(int i)
 44 {
 45     if( i < 0 )
 46     {
 47         throw -1;
 48     }
 49     
 50     if( i > 100 )
 51     {
 52         throw -2;
 53     }
 54     
 55     if( i == 11 )
 56     {
 57         throw -3;
 58     }
 59     
 60     cout << "Run func..." << endl;
 61 }
 62 
 63 /* 使用自定义的类类型来优化 */
 64 void MyFunc(int i)
 65 {
 66     try
 67     {
 68         func(i);
 69     }
 70     catch(int i)
 71     {
 72         switch(i)
 73         {
 74             case -1:
 75                 throw Exception(-1, "Invalid Parameter");  // 直接调用构造函数生成异常对象;
 76                 break;
 77             case -2:
 78                 throw Exception(-2, "Runtime Exception");  // 直接调用构造函数生成异常对象;
 79                 break;
 80             case -3:
 81                 throw Exception(-3, "Timeout Exception");  // 直接调用构造函数生成异常对象;
 82                 break;
 83         }
 84     }
 85 }
 86 
 87 int main(int argc, char *argv[])
 88 {
 89     try
 90     {
 91         MyFunc(11);
 92     }
 93     catch(const Exception& e)  // 这里使用异常类,为了防止拷贝构造、提高程序效率,用引用,同时也为了防止无休止递归调用导致栈溢出;
 94     {
 95         cout << "Exception Info: " << endl;  // Exception Info:
 96         cout << "   ID: " << e.id() << endl;  // ID: -3;
 97         cout << "   Description: " << e.description() << endl;  // Description: Timeout Exception;
 98     }
 99     catch(const Base& e)  // 如果把父类放到子类上面,则编译器显示:
100                           // warning: exception of type ‘Exception‘ will be caught(子类这一行)
101                           // warning: by earlier handler for ‘Base‘ (父类这一行);
102     {
103         cout << "catch(const Base& e)" << endl;
104     }
105     
106     return 0;
107 }

    1,异常信息更加丰富,更加方便的定位问题所在;

    2,工程开发中,一般以自定义类类型来描述可能出现的异常;

    3,工程开发中,子类上,父类下;

    4,本例告诉大家实际工程开发中定义完异常类的层次结构之后,如何来进行使用;

   

8,C++ 标准库中的异常类:

    1,C++ 标准库中提供了实用异常类族;

    2,标准库中的异常都是从 exception 类派生的;

    3,exception 类有两个主要的分支:

       1,logic_error:

           1,常用于程序中的可避免逻辑错误;

              1,空指针,函数参数错误,下标越界等;

       2,runtime_error:

           1,常用于程序中无法避免的恶心错误;

              1,运算产生越界、溢出等;

    4,标准库中的异常类继承图:

技术分享图片 

       1,可以查看 C++ 标准库文档,看异常怎么使用;

      

9,标准库中的异常使用编程实验(用异常类优化数组类):

    1,Array.h 的优化:

 1 #ifndef _ARRAY_H_
 2 #define _ARRAY_H_
 3 
 4 #include <stdexcept>  // 标准库中的异常类头文件;
 5 
 6 using namespace std;
 7 
 8 template
 9 < typename T, int N >
10 class Array
11 {
12     T m_array[N];
13 public:
14     int length() const;
15     bool set(int index, T value);
16     bool get(int index, T& value);
17     T& operator[] (int index);
18     T operator[] (int index) const;
19     virtual ~Array();
20 };
21 
22 template
23 < typename T, int N >
24 int Array<T, N>::length() const
25 {
26     return N;
27 }
28 
29 template
30 < typename T, int N >
31 bool Array<T, N>::set(int index, T value)
32 {
33     bool ret = (0 <= index) && (index < N);
34     
35     if( ret )
36     {
37         m_array[index] = value;
38     }
39     
40     return ret;
41 }
42 
43 template
44 < typename T, int N >
45 bool Array<T, N>::get(int index, T& value)
46 {
47     bool ret = (0 <= index) && (index < N);
48     
49     if( ret )
50     {
51         value = m_array[index];
52     }
53     
54     return ret;
55 }
56 
57 template
58 < typename T, int N >
59 T& Array<T, N>::operator[] (int index)
60 {
61     if( (0 <= index) && (index < N) )
62     {
63         return m_array[index];  // 这里之前没有验证 index 是否合法,因为验证了也没办法处理;
64     }
65     else
66     {
67         throw out_of_range("T& Array<T, N>::operator[] (int index)");
68     }
69 }
70 
71 template
72 < typename T, int N >
73 T Array<T, N>::operator[] (int index) const
74 {
75     if( (0 <= index) && (index < N) )
76     {
77         return m_array[index];  // 这里之前没有验证 index 是否合法,因为验证了也没办法处理;
78     }
79     else
80     {
81         throw out_of_range("T Array<T, N>::operator[] (int index) const");
82     }
83 }
84 
85 template
86 < typename T, int N >
87 Array<T, N>::~Array()
88 {
89 
90 }
91 
92 #endif

    2,HeapArray.h 的优化:

  1 #ifndef _HEAPARRAY_H_
  2 #define _HEAPARRAY_H_
  3 
  4 #include <stdexcept>  // 添加标准头文件;
  5 
  6 using namespace std;
  7 
  8 template
  9 < typename T >
 10 class HeapArray
 11 {
 12 private:
 13     int m_length;
 14     T* m_pointer;
 15     
 16     HeapArray(int len);
 17     HeapArray(const HeapArray<T>& obj);
 18     bool construct();
 19 public:
 20     static HeapArray<T>* NewInstance(int length); 
 21     int length() const;
 22     bool get(int index, T& value);
 23     bool set(int index ,T value);
 24     T& operator [] (int index);
 25     T operator [] (int index) const;
 26     HeapArray<T>& self();
 27     const HeapArray<T>& self() const;  // 要考虑成员函数有没有必要成为 const 函数,const 函数主要是给 cosnt 函数调用;
 28     ~HeapArray();
 29 };
 30 
 31 template
 32 < typename T >
 33 HeapArray<T>::HeapArray(int len)
 34 {
 35     m_length = len;
 36 }
 37 
 38 template
 39 < typename T >
 40 bool HeapArray<T>::construct()
 41 {   
 42     m_pointer = new T[m_length];
 43     
 44     return m_pointer != NULL;
 45 }
 46 
 47 template
 48 < typename T >
 49 HeapArray<T>* HeapArray<T>::NewInstance(int length) 
 50 {
 51     HeapArray<T>* ret = new HeapArray<T>(length);
 52     
 53     if( !(ret && ret->construct()) ) 
 54     {
 55         delete ret;
 56         ret = 0;
 57     }
 58         
 59     return ret;
 60 }
 61 
 62 template
 63 < typename T >
 64 int HeapArray<T>::length() const
 65 {
 66     return m_length;
 67 }
 68 
 69 template
 70 < typename T >
 71 bool HeapArray<T>::get(int index, T& value)
 72 {
 73     bool ret = (0 <= index) && (index < length());
 74     
 75     if( ret )
 76     {
 77         value = m_pointer[index];
 78     }
 79     
 80     return ret;
 81 }
 82 
 83 template
 84 < typename T >
 85 bool HeapArray<T>::set(int index, T value)
 86 {
 87     bool ret = (0 <= index) && (index < length());
 88     
 89     if( ret )
 90     {
 91         m_pointer[index] = value;
 92     }
 93     
 94     return ret;
 95 }
 96 
 97 template
 98 < typename T >
 99 T& HeapArray<T>::operator [] (int index)
100 {
101     if( (0 <= index) && (index < length()) )
102     {
103         return m_pointer[index];  // 优化这里,越界抛异常;
104     }
105     else
106     {
107         throw out_of_range("T& HeapArray<T>::operator [] (int index)");
108     }
109 }
110 
111 template
112 < typename T >
113 T HeapArray<T>::operator [] (int index) const
114 {
115     if( (0 <= index) && (index < length()) )
116     {
117         return m_pointer[index];  // 优化这里,越界抛异常;
118     }
119     else
120     {
121         throw out_of_range("T HeapArray<T>::operator [] (int index) const");
122     }
123 }
124 
125 template
126 < typename T >
127 HeapArray<T>& HeapArray<T>::self()
128 {
129     return *this;
130 }
131 
132 template
133 < typename T >
134 const HeapArray<T>& HeapArray<T>::self() const
135 {
136     return *this;
137 }
138 
139 template
140 < typename T >
141 HeapArray<T>::~HeapArray()
142 {
143     delete[]m_pointer;
144 }
145 
146 #endif

    3,使用:

 1 #include <iostream>
 2 #include <string>
 3 #include "Array.h"
 4 #include "HeapArray.h"
 5 
 6 using namespace std;
 7 
 8 void TestArray()
 9 {
10     Array<int, 5> a;
11     
12     for(int i=0; i<a.length(); i++)
13     {
14         a[i] = i;  // 如果访问越界,则编译器显示: terminate called after throwing an instance of ‘std::out_of_range‘ what():  T& Array<T, N>::operator[] (int index);已放弃
15     }
16         
17     for(int i=0; i<a.length(); i++)
18     {
19         cout << a[i] << endl;
20     }
21 }
22 
23 void TestHeapArray()
24 {
25     HeapArray<double>* pa = HeapArray<double>::NewInstance(5);
26     
27     if( pa != NULL )
28     {
29         HeapArray<double>& array = pa->self();
30         
31         for(int i=0; i<array.length(); i++)
32         {
33             array[i] = i;
34         }
35             
36         for(int i=0; i<array.length(); i++)
37         {
38             cout << array[i] << endl;
39         }
40     }
41     
42     delete pa;
43 }
44 
45 int main(int argc, char *argv[])
46 {
47     
48     try
49     {
50         TestArray();
51         
52         cout << endl;
53         
54         TestHeapArray();
55     }
56     catch(...)
57     {
58         cout << "Exception" << endl;
59     }
60     
61     return 0;
62 }

    1,在以后开发需要使用标准库的时候,要有当前开发所使用的函数或类会不会出现异常这个意识,这个时候需要查标准库的文档,看看每个函数的说明,每个类的说明;

   

10,小结:

    1,catch 语句块中可以抛出异常;

    2,异常的类型可以是自定义类类型;

    3,赋值兼容性原则在异常匹配中依然适用;

    4,标准库中的异常都是从 exception 类派生的;

C++中的异常处理(下)

原文:https://www.cnblogs.com/dishengAndziyu/p/10919877.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!