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, 异常的重新解释编程实验:
- #include <iostream>
- #include <string>
- using namespace std;
- void Demo()
- {
- try
- {
- try
- {
- throw 'c';
- }
- catch(int i)
- {
- cout <<"Inner: catch(int i)" << endl;
- throw i;
- }
- catch(...)
- {
- cout << "Inner: catch(...)" << endl;
- throw;
- }
- }
- catch(...)
- {
- cout << "Outer: catch(...)" << endl;
- }
- }
- /*
- 假设: 当前的函数是第三方库中的函数, 因此, 我们无法修改源代码
- 函数名: void func(int i)
- 抛出异常的类型: int
- -1 ==》 参数异常
- -2 ==》 运行异常
- -3 ==》 超时异常
- */
- /* 第三方库函数, 编写好后不能修改, 因为我们一般没有源代码, 这里仅是用于模拟 */
- void func(int i)
- {
- if( i < 0 )
- {
- throw -1;
- }
- if( i> 100 )
- {
- throw -2;
- }
- if( i == 11 )
- {
- throw -3;
- }
- cout <<"Run func..." << endl; // 没有异常, 则执行 func() 函数功能;
- }
- /* 不能修改 func() 函数, 则我们定义 MyFunc() 函数重解释 func() 的异常 */
- void MyFunc(int i)
- {
- try
- {
- func(i); // 直接通过第三方库中的 func() 来实现我们需要的功能;
- }
- catch(int i)
- {
- switch(i)
- {
- case -1:
- throw "Invalid Parameter";
- break;
- case -2:
- throw "Runtime Exception";
- break;
- case -3:
- throw "Timeout Exception";
- break;
- }
- }
- }
- int main(int argc, char *argv[])
- {
- // Demo();
- try
- {
- MyFunc(11); // 如果在这里调用 func(11), 则下面 catch 语句块中会打印: Exception Info: -3; 这样就不能立刻反应出来出了什么事儿, 此时要去找 func() 中的文档说明, 这样的开发是非常痛苦的;
- }
- catch(const char* cs)
- {
- cout << "Exception Info:" << cs << endl; // 打印: Exception Info: Timeout Exception
- }
- return 0;
- }
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, 类型的异常编程实验:
- #include <iostream>
- #include <string>
- using namespace std;
- class Base
- {
- };
- /* 定义异常类 */
- class Exception : public Base
- {
- int m_id;
- string m_desc;
- public:
- Exception(int id, string desc)
- {
- m_id = id;
- m_desc = desc;
- }
- int id() const
- {
- return m_id;
- }
- string description() const
- {
- return m_desc;
- }
- };
- /*
- 假设: 当前的函数式第三方库中的函数, 因此, 我们无法修改源代码
- 函数名: void func(int i)
- 抛出异常的类型: int
- -1 ==》 参数异常
- -2 ==》 运行异常
- -3 ==》 超时异常
- */
- /* 第三方库函数, 编写好后不能修改, 因为我们一般没有源代码, 这里仅是用于模拟 */
- void func(int i)
- {
- if( i <0 )
- {
- throw -1;
- }
- if( i> 100 )
- {
- throw -2;
- }
- if( i == 11 )
- {
- throw -3;
- }
- cout <<"Run func..." << endl;
- }
- /* 使用自定义的类类型来优化 */
- void MyFunc(int i)
- {
- try
- {
- func(i);
- }
- catch(int i)
- {
- switch(i)
- {
- case -1:
- throw Exception(-1, "Invalid Parameter"); // 直接调用构造函数生成异常对象;
- break;
- case -2:
- throw Exception(-2, "Runtime Exception"); // 直接调用构造函数生成异常对象;
- break;
- case -3:
- throw Exception(-3, "Timeout Exception"); // 直接调用构造函数生成异常对象;
- break;
- }
- }
- }
- int main(int argc, char *argv[])
- {
- try
- {
- MyFunc(11);
- }
- catch(const Exception& e) // 这里使用异常类, 为了防止拷贝构造, 提高程序效率, 用引用, 同时也为了防止无休止递归调用导致栈溢出;
- {
- cout << "Exception Info:" << endl; // Exception Info:
- cout << "ID:" << e.id() << endl; // ID: -3;
- cout << "Description:" << e.description() << endl; // Description: Timeout Exception;
- }
- catch(const Base& e) // 如果把父类放到子类上面, 则编译器显示:
- // warning: exception of type 'Exception' will be caught(子类这一行)
- // warning: by earlier handler for 'Base' (父类这一行);
- {
- cout << "catch(const Base& e)" << endl;
- }
- return 0;
- }
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 的优化:
- #ifndef _ARRAY_H_
- #define _ARRAY_H_
- #include <stdexcept> // 标准库中的异常类头文件;
- using namespace std;
- template
- <typename T, int N>
- class Array
- {
- T m_array[N];
- public:
- int length() const;
- bool set(int index, T value);
- bool get(int index, T& value);
- T& operator[] (int index);
- T operator[] (int index) const;
- virtual ~Array();
- };
- template
- <typename T, int N>
- int Array<T, N>::length() const
- {
- return N;
- }
- template
- <typename T, int N>
- bool Array<T, N>::set(int index, T value)
- {
- bool ret = (0 <= index) && (index <N);
- if( ret )
- {
- m_array[index] = value;
- }
- return ret;
- }
- template
- < typename T, int N>
- bool Array<T, N>::get(int index, T& value)
- {
- bool ret = (0 <= index) && (index <N);
- if( ret )
- {
- value = m_array[index];
- }
- return ret;
- }
- template
- < typename T, int N>
- T& Array<T, N>::operator[] (int index)
- {
- if( (0 <= index) && (index <N) )
- {
- return m_array[index]; // 这里之前没有验证 index 是否合法, 因为验证了也没办法处理;
- }
- else
- {
- throw out_of_range("T& Array<T, N>::operator[] (int index)");
- }
- }
- template
- <typename T, int N>
- T Array<T, N>::operator[] (int index) const
- {
- if( (0 <= index) && (index <N) )
- {
- return m_array[index]; // 这里之前没有验证 index 是否合法, 因为验证了也没办法处理;
- }
- else
- {
- throw out_of_range("T Array<T, N>::operator[] (int index) const");
- }
- }
- template
- <typename T, int N>
- Array<T, N>::~Array()
- {
- }
- #endif
2,HeapArray.h 的优化:
- #ifndef _HEAPARRAY_H_
- #define _HEAPARRAY_H_
- #include <stdexcept> // 添加标准头文件;
- using namespace std;
- template
- <typename T>
- class HeapArray
- {
- private:
- int m_length;
- T* m_pointer;
- HeapArray(int len);
- HeapArray(const HeapArray<T>& obj);
- bool construct();
- public:
- static HeapArray<T>* NewInstance(int length);
- int length() const;
- bool get(int index, T& value);
- bool set(int index ,T value);
- T& operator [] (int index);
- T operator [] (int index) const;
- HeapArray<T>& self();
- const HeapArray<T>& self() const; // 要考虑成员函数有没有必要成为 const 函数, const 函数主要是给 cosnt 函数调用;
- ~HeapArray();
- };
- template
- <typename T>
- HeapArray<T>::HeapArray(int len)
- {
- m_length = len;
- }
- template
- <typename T>
- bool HeapArray<T>::construct()
- {
- m_pointer = new T[m_length];
- return m_pointer != NULL;
- }
- template
- <typename T>
- HeapArray<T>* HeapArray<T>::NewInstance(int length)
- {
- HeapArray<T>* ret = new HeapArray<T>(length);
- if( !(ret && ret->construct()) )
- {
- delete ret;
- ret = 0;
- }
- return ret;
- }
- template
- <typename T>
- int HeapArray<T>::length() const
- {
- return m_length;
- }
- template
- <typename T>
- bool HeapArray<T>::get(int index, T& value)
- {
- bool ret = (0 <= index) && (index <length());
- if( ret )
- {
- value = m_pointer[index];
- }
- return ret;
- }
- template
- < typename T>
- bool HeapArray<T>::set(int index, T value)
- {
- bool ret = (0 <= index) && (index <length());
- if( ret )
- {
- m_pointer[index] = value;
- }
- return ret;
- }
- template
- < typename T>
- T& HeapArray<T>::operator [] (int index)
- {
- if( (0 <= index) && (index <length()) )
- {
- return m_pointer[index]; // 优化这里, 越界抛异常;
- }
- else
- {
- throw out_of_range("T& HeapArray<T>::operator [] (int index)");
- }
- }
- template
- <typename T>
- T HeapArray<T>::operator [] (int index) const
- {
- if( (0 <= index) && (index <length()) )
- {
- return m_pointer[index]; // 优化这里, 越界抛异常;
- }
- else
- {
- throw out_of_range("T HeapArray<T>::operator [] (int index) const");
- }
- }
- template
- <typename T>
- HeapArray<T>& HeapArray<T>::self()
- {
- return *this;
- }
- template
- <typename T>
- const HeapArray<T>& HeapArray<T>::self() const
- {
- return *this;
- }
- template
- <typename T>
- HeapArray<T>::~HeapArray()
- {
- delete[]m_pointer;
- }
- #endif
3, 使用:
- #include <iostream>
- #include <string>
- #include "Array.h"
- #include "HeapArray.h"
- using namespace std;
- void TestArray()
- {
- Array<int, 5> a;
- for(int i=0; i<a.length(); i++)
- {
- a[i] = i; // 如果访问越界, 则编译器显示: terminate called after throwing an instance of 'std::out_of_range' what(): T& Array<T, N>::operator[] (int index); 已放弃
- }
- for(int i=0; i<a.length(); i++)
- {
- cout <<a[i] << endl;
- }
- }
- void TestHeapArray()
- {
- HeapArray<double>* pa = HeapArray<double>::NewInstance(5);
- if( pa != NULL )
- {
- HeapArray<double>& array = pa->self();
- for(int i=0; i<array.length(); i++)
- {
- array[i] = i;
- }
- for(int i=0; i<array.length(); i++)
- {
- cout << array[i] << endl;
- }
- }
- delete pa;
- }
- int main(int argc, char *argv[])
- {
- try
- {
- TestArray();
- cout << endl;
- TestHeapArray();
- }
- catch(...)
- {
- cout << "Exception" << endl;
- }
- return 0;
- }
1, 在以后开发需要使用标准库的时候, 要有当前开发所使用的函数或类会不会出现异常这个意识, 这个时候需要查标准库的文档, 看看每个函数的说明, 每个类的说明;
10, 小结:
1,catch 语句块中可以抛出异常;
2, 异常的类型可以是自定义类类型;
3, 赋值兼容性原则在异常匹配中依然适用;
4, 标准库中的异常都是从 exception 类派生的;
来源: http://www.bubuko.com/infodetail-3070378.html