C++中的异常处理(下)
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 < )
{
throw -;
} if( i > )
{
throw -;
} if( i == )
{
throw -;
} cout << "Run func..." << endl; // 没有异常,则执行 func() 函数功能;
} /* 不能修改 func() 函数,则我们定义 MyFunc() 函数重解释 func() 的异常 */
void MyFunc(int i)
{
try
{
func(i); // 直接通过第三方库中的 func() 来实现我们需要的功能;
}
catch(int i)
{
switch(i)
{
case -:
throw "Invalid Parameter";
break;
case -:
throw "Runtime Exception";
break;
case -:
throw "Timeout Exception";
break;
}
}
} int main(int argc, char *argv[])
{
// Demo(); try
{
MyFunc(); // 如果在这里调用 func(11),则下面 catch 语句块中会打印:Exception Info: -3; 这样就不能立刻反应出来出了什么事儿,此时要去找 func() 中的文档说明,这样的开发是非常痛苦的;
}
catch(const char* cs)
{
cout << "Exception Info: " << cs << endl; // 打印:Exception Info: Timeout Exception
} return ;
}
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 < )
{
throw -;
} if( i > )
{
throw -;
} if( i == )
{
throw -;
} cout << "Run func..." << endl;
} /* 使用自定义的类类型来优化 */
void MyFunc(int i)
{
try
{
func(i);
}
catch(int i)
{
switch(i)
{
case -:
throw Exception(-, "Invalid Parameter"); // 直接调用构造函数生成异常对象;
break;
case -:
throw Exception(-, "Runtime Exception"); // 直接调用构造函数生成异常对象;
break;
case -:
throw Exception(-, "Timeout Exception"); // 直接调用构造函数生成异常对象;
break;
}
}
} int main(int argc, char *argv[])
{
try
{
MyFunc();
}
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 ;
}
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 = ( <= 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 = ( <= index) && (index < N); if( ret )
{
value = m_array[index];
} return ret;
} template
< typename T, int N >
T& Array<T, N>::operator[] (int index)
{
if( ( <= 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( ( <= 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 = ;
} 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 = ( <= index) && (index < length()); if( ret )
{
value = m_pointer[index];
} return ret;
} template
< typename T >
bool HeapArray<T>::set(int index, T value)
{
bool ret = ( <= index) && (index < length()); if( ret )
{
m_pointer[index] = value;
} return ret;
} template
< typename T >
T& HeapArray<T>::operator [] (int index)
{
if( ( <= 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( ( <= 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, > a; for(int i=; 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=; i<a.length(); i++)
{
cout << a[i] << endl;
}
} void TestHeapArray()
{
HeapArray<double>* pa = HeapArray<double>::NewInstance(); if( pa != NULL )
{
HeapArray<double>& array = pa->self(); for(int i=; i<array.length(); i++)
{
array[i] = i;
} for(int i=; 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 ;
}
1,在以后开发需要使用标准库的时候,要有当前开发所使用的函数或类会不会出现异常这个意识,这个时候需要查标准库的文档,看看每个函数的说明,每个类的说明;
10,小结:
1,catch 语句块中可以抛出异常;
2,异常的类型可以是自定义类类型;
3,赋值兼容性原则在异常匹配中依然适用;
4,标准库中的异常都是从 exception 类派生的;
C++中的异常处理(下)的更多相关文章
- C++中的异常处理(下)
array.h #ifndef _ARRAY_H_ #define _ARRAY_H_ #include <stdexcept> using namespace std; template ...
- 第65课 C++中的异常处理(下)
1. C++中的异常处理 (1)catch语句块可以抛出异常 ①catch中获捕的异常可以被重新抛出 ②抛出的异常需要外层的try-catch块来捕获 ③catch(…)块中抛异常的方法是throw; ...
- C++中的异常处理(一)
来自:CSDN 卡尔 后续有C++中的异常处理(二)和C++中的异常处理(三),C++中的异常处理(二)是对动态分配内存后内部发生错误情况的处理方法,C++中的异常处理(三)中是使用时的异常说明. ...
- java 中的异常处理
一. 异常的概念和Java异常体系结构 异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架, 是Java语言健壮性的一个重要体现. Java把 ...
- Delphi中的异常处理(10种异常来源、处理、精确处理)
一.异常的来源 在Delphi应用程序中,下列的情况都比较有可能产生异常. 1.文件处理 2.内存分配 3.windows资源 4.运行时创建对象和窗体 5.硬件和操作系统冲突 6.网络问题 7.数据 ...
- 【ASP.NET Web API教程】4.3 ASP.NET Web API中的异常处理
原文:[ASP.NET Web API教程]4.3 ASP.NET Web API中的异常处理 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内 ...
- 【转】Java中关于异常处理的十个最佳实践
原文地址:http://www.searchsoa.com.cn/showcontent_71960.htm 导读:异常处理是书写强健Java应用的一个重要部分,Java许你创建新的异常,并通过使用 ...
- T-SQL编程中的异常处理-异常捕获(catch)与抛出异常(throw)
本文出处: http://www.cnblogs.com/wy123/p/6743515.html T-SQL编程与应用程序一样,都有异常处理机制,比如异常的捕获与异常的抛出,本文简单介绍异常捕获与异 ...
- web应用中的异常处理
楼主前几天写了一篇“Java子线程中的异常处理(通用)”文章,介绍了在多线程环境下3种通用的异常处理方法. 但是平时大家的工作一般是基于开发框架进行的(比如Spring MVC,或Spring Boo ...
- Python基础---python中的异常处理
Python中的异常处理 一.什么是异常处理 python解释器检测到错误,触发异常(也允许程序员自己触发异常) 程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关) ...
随机推荐
- C# 字符串Trim进阶
private void button1_Click(object sender, EventArgs e) {//去掉字符串头尾指定字符 string MyInfo= "--中华人民共和国 ...
- 同一客户端多个git账号的配置
同一客户端多个git账号的配置 同一客户端多个git账号的配置 步骤一:用ssh-keygen命令生成一组新的id_rsa_new和id_rsa_new.pub. 1 ssh-keygen -t rs ...
- echarts改变图例位置
只需要legend属性中修改如下几个示数即可: legend:{ orient:"horizontal", x:'right', y:' center', width:'100', ...
- CSS3中resize属性
说明: resize属性是指定一个元素是否可由用户调整大小的. 语法: resize:none | both | horizontal | vertical none:用户不可一调整元素的尺寸(默认值 ...
- shell判断/bin目录下date文件是否存在
- 前端移动开发--viewpoint
移动开发时,一般都会在头部加载这样一行meta标签 <meta name="viewport" content="width=device-width, initi ...
- vue+element-ui 实现分页(根据el-table内容变换的分页)
官方例子 官方提示: 设置layout,表示需要显示的内容,用逗号分隔,布局元素会依次显示.prev表示上一页,next为下一页,pager表示页码列表,除此以外还提供了jumper和total,si ...
- Sublime Text 注册及使用相关
sublime text3 注册码 2019-07-01 注册码可以直接用 地址: 2019-07-01 亲测可用 2019-07-18 亲测可用 -– BEGIN LICENSE -– Die So ...
- cnpm 安装和 command not found
安装cnpm出错 > $ npm install -g cnpm --registry=https://registry.npm.taobao.org 按照淘宝 NPM 镜像安装,cnpm -v ...
- python字符串非空判断
1. 字符串非空判断 2. list 非空判断