此文是文章《C++查缺补漏之异常》:http://blog.csdn.net/ii1245712564/article/details/44617881的后续

1.异常的重新抛出

可能单个catch不能完全处理一个异常,于是我们需要将这个其他具有更强处理能力的catch进行处理,那么这个异常就不止经过一个catch了,需要将异常重新抛出,抛出给其他的处理代码继续处理,这里用到的语句就是一个没有参数的throw语句。
try{
/** do something */
throw exception
}catch(exception & err)
{
/** deal the exception */
throw// rethrow the exception
}
注意事项:在异常重新抛出的时候,抛出的不是当前catch的异常形参,而是原本的异常对象,重新抛出的异常是由异常对象的动态类型决定的,而不是catch异常形参的静态类型决定的,就是catch的异常说明符是基类的,而异常对象是派生类的,那么重新抛出的异常对象是派生类的,而不是基类的!
要是不是在一个catch子句里面用throw语句会怎么样呢?那么程序将会调用terminate标准库函数,程序马上奔溃
下面来看一个例子:
#include <iostream>
using namespace std;class A
{
public:A(int _number):number(_number){};int number;
};void testFunc()
{try{throw A(10);}catch(A & err){cout<<"In the testFunc the number is :"<<err.number<<endl;err.number =11;throw ;//rethrow the execption }
}int main(int argc, char const *argv[])
{try{testFunc();}catch(A & err){cout<<"In the main Function the number is:"<<err.number<<endl;}while(1);return 0;
}

运行结果为:

"In the testFunc the number is  :10"
"In the main Function the number is:11"
这里的异常对象从testFunc里面抛出,在testFunc里面进行第一次处理以后,再重新抛出,在main里面进行第二次处理

2.捕获所有异常的处理代码

在我们的程序中,会发生各种各样的异常,我们用有限的catch语句来捕获不按规矩出现的异常,明显是不能完全覆盖的,于是就出现了一个叫可以捕获所有异常的catch子句:
try{
/** do something then throw exception */
}catch(...)
{
/** catch all kind exceptions */
}
就是上面的catch(...)语句可以捕获所有种类的异常,我们可以使用这种catch子句来为每种类型的异常做一些局部工作,再重新抛出
注意:catch(...)应该总是放在所有catch子句的最后,否则任何在它之后的catch子句都不能被激活.

3.函数测试块与构造函数

我们的异常可以发生在程序的任何地方,包括构造函数,构造函数里面的try,catch语句是无法捕获初始化列表里面的异常的,要是我们想捕获在初始化列表里面的异常,我们需要编写函数测试块,写法如下:
ClassName
try:{初始化列表}
{
/** 构造函数内部初始化工作 */
}catch(exception)
{
/** 异常的处理代码 */
}
下面举一个栗子:
#include <iostream>
#include <stdexcept>
using namespace std;class A
{
public:A()try : ptr(new int[-1]){cout<<"constructing class A object"<<endl;}catch(bad_alloc & err){cout<<"Get the bad_alloc exception "<<err.what()<<endl;}catch(...){cout<<"Get teh unknown exception"<<endl;}
private:int * ptr;
};int main(int argc, char const *argv[])
{A a;while(1);return 0;
}

在构造A类型的对象的时候,因为是new int[-1],那么一定会抛出异常,最后被第一个catch子句捕获,注意构造函数测试块是唯一检测构造函数初始化列表异常的方法。

4.异常说明

查看普通函数声明的时候,不能确定函数能抛出什么类型的异常,但是为了编写适当的catch子句,了解函数时候抛出异常以及抛出什么异常很有用,异常说明指定,如果函数抛出异常,那么被抛出的异常将会是包含在说明中的一种,或者其中的派生类

4.1定义异常说明

异常说明跟在函数的形参表之后,一个异常说明在关键字throw之后跟着一个由圆括号括住的异常类型列表
void recoup(int) throw(runtime_error);
这个声明指出,recoup是一个形参为int,返回值为void,只能抛出runtime_error,或者runtime_error派生异常的函数
void no_problem() throw();
这个说明指出,no_problem不抛出任何异常
void any_exception();
这个说明指出any_exception可以抛出任何异常。
注意:函数的声明和定义都要有相同的异常说明!

4.2违反异常说明

我们虽然限制了函数可以抛出那些异常,但是到底抛出什么异常是在程序运行中才能决定的,如果程序运行中抛出了异常说明列表之外的异常,那么就会调用标准库函数unexcepted。默认情况下unexcepted函数会调用terminate函数

4.3异常说明与成员函数

像非成员函数一样,成员函数的声明的异常说明是跟在函数形参表之后的,列入C++标准库bad_alloc类定义的为所有成员函数都有空异常说明
class bad_alloc : public exception
{
public:
bad_alloc() throw();
/** other functions */
};

4.4异常说明与虚函数

对于派生类虚函数的异常声明不必与基类虚函数的异常声明完全相同。派生类虚函数的异常声明必须要比基类虚函数的异常声明更加的严格,或者二者相同。
这个限制保证,在使用基类指针动态调用派生类的虚函数时,不会抛出基类虚函数异常声明之外的异常,不然只用基类接口这种设定就不实际了,还需要根据相应的派生类增加相应的异常处理。倒不如直接在基类里面全部包含。
下面看一个例子:
#include <iostream>
#include <stdexcept>using namespace std;class A
{
public:A(){}virtual void func() throw(bad_alloc , runtime_error){cout<<"Hello World"<<endl;}};class B : public A
{
public:B(){}void func() throw(bad_alloc ,runtime_error , logic_error){}
};int main(int argc, char const *argv[])
{A a;B b;return 0;
}

上面的B派生于A,但是B中func函数抛出的异常种类却比A中多,我们编译一下:

C:\Users\Administrator\Desktop\exception.cc:21:10: error: looser throw specifier for 'virtual void B::func() throw (std::bad_alloc, std::runtime_error, std::logic_error)'
     void func() throw(bad_alloc ,runtime_error , logic_error)
          ^
C:\Users\Administrator\Desktop\exception.cc:10:18: error:   overriding 'virtual void A::func() throw (std::bad_alloc, std::runtime_error)'
     virtual void func() throw(bad_alloc , runtime_error)
发现报错了,上面写着B中func的更松的异常说明

要是把B的func改为这样呢
void func() throw(bad_alloc)
{/** something */}
编译通过!
要是改成这样呢
void func() throw(logic_error)
{/** something */}
编译出错,跟第一个一样的错误
所以我们得出结论,基类虚函数的异常说明是对应派生类虚函数的异常说明的一个超集!

5.函数指针与异常说明

异常说明是函数类型的一部分,我们可以在函数指针的定义中加入异常说明:
void (*funcPtr)(int) throw(runtime_error);
在用另一个指针初始化函数异常声明指针的时候,或者将后者赋值给函数地址的时候,二者的异常说明不必相同,但是源指针的异常说明必须至少与目标指针一样严格!
下面我们来看一些例子
void func(int) throw(runtime_error);// declare a func
void (*funcPtr)(int) = func;// ok
void (*funcPtr)(int) throw(runtime error) = func;// ok
void (*funcPtr)(int) throw(runtime_error , logic_error) = func;// ok
void (*funcPtr)(int) throw() = func;//error
上面我们看到前三个指针的赋值都是可行的,最后一个赋值是不行的,因为funcPtr指针不能抛出任何异常,但是func能抛出一个runtime_error异常。我们假如这样是可行的,让一个不能抛出任何异常的函数指针指向一个可以抛出异常的函数,那个在把这个函数指针用在程序中,那到底这个函数抛不抛出异常呢,现在就行不通了

C++查缺补漏之异常(续)相关推荐

  1. EFCore查缺补漏(二):查询

    相关文章: EFCore查缺补漏 第 20 轮 TechEmpower 评测结果出炉了,ASP.NET Core 的 Plaintext 成绩名列前茅,带着 EFCore 的测试却在 Single q ...

  2. JAVA核心,200例,查缺补漏

    适用于想要查缺补漏的人:本已经掌握的技术,但是不知道如何表达的人:不断完善技自己,顺带梳理下答案. 主要包括以下模块:Java基础.容器.多线程.反射.对象拷贝.Java Web模块,异常.网络.设计 ...

  3. 查缺补漏系统学习 EF Core 6 - 数据查询

    这是 EF Core 系列的第四篇文章,上一篇文章讲述了 EF Core 中的实体迁移与数据播种. 这篇文章盘点一下 EF Core 的几种数据查询方式,内容较多分上下两篇. 点击上方或后方蓝字,阅读 ...

  4. java基础的查缺补漏

    打好基础,加油加油加油! 文章目录 前言 day1(6.16test,7.2) day2(7.3) java运行机制 java关键字 变量定义 常量定义 7.4 7.6 总结 前言 为了方便自己回顾知 ...

  5. Python高效技巧(三)---查缺补漏(时间处理、shutill模块、高阶函数、装饰器)

    Python高效技巧 前言: 函数 1.可接受任意数量参数的函数和关键词参数 2.匿名函数 lambda 二.其他 1.关于序列的各种方法 2.产生器表达式 三. 查缺补漏 1.时间处理 1. cal ...

  6. 就业前夕——Java查缺补漏(从头学)

    Java查缺补漏 变量 局部变量 方法或语句块内部定义的变量. 生命周期从声明位置开始到方法或语句块结束. 使用前必须先初始化. 成员变量(实例变量) 方法外部.类内部定义的变量(未被static修饰 ...

  7. Java 基础开发技术查缺补漏笔记

    暑假期间,个人对一些未来研究生阶段可能会常用的编程技术进行重新一轮的系统复习和学习,及希望能够查缺补漏,有所提升.本文也是作为复习和学习过程中的笔记,用于长久的记录.不排除其中可能含有部分疏漏和错误, ...

  8. I2C总线学习—查缺补漏—S3C2440的I2C控制器

    I2C总线学习-查缺补漏-S3C2440的I2C控制器                  学习了IIC总线协议的理论部分,觉得应该学习具体操作2440的IIC控制器,毕竟最终都是为了学习S3C2440 ...

  9. I2C总线学习—查缺补漏—应答信号ACK

    I2C总线学习-查缺补漏-应答信号ACK           IIC协议规定,当主机作为接收设备时,主机对最后一个字节不应答,以向发送设备(从设备)标识数据传送结束.这是因为每次传输都应得到应答信号后 ...

最新文章

  1. LeetCode简单题之检查单词是否为句中其他单词的前缀
  2. Android众说纷纭分辨率
  3. python3 字符串 转 整型
  4. ApiDoc官方文档
  5. python 将pdf分页后插入至word中
  6. 铜线越长发电量越多,6千米长的铜线能让电灯泡发光吗?
  7. nagios监控slave(借助脚本)
  8. Toonz开源,Apple开源CareKit,以及更多新闻
  9. db2 linux 导入数据_实现DB2数据库迁移之导入步骤在Linux下
  10. PHP+MySQL存储数据出现中文乱码的问题
  11. Ubuntu20.04安装ROS Noetic
  12. paip.java 调用c++ dll so总结
  13. 用注册机注册Keil
  14. html星空代码在线,怎么操作html星空特效代码
  15. 如何才能更好发挥WinRunner,实现真正的自动化测试
  16. 一文读懂《“十四五”软件和信息技术服务业发展规划》
  17. 单例模式--懒汉模式和饿汉模式
  18. html设置列表编号起始值,Word多级编号怎么设置,要按我的要求作为起始值?
  19. android 程序启动监听,监听开机自动启动应用
  20. uni-app 使用外部.js文件定义全局变量和全局方法

热门文章

  1. 招商管理、智慧招商、精准招商、地图招商、crm系统、企业画像、拜访跟进、销售简报、营销触达、坐席外呼、短信、签名、公海、客户、合同、业绩、员工、权限管理、角色、部门、费用、消息、交接、axure原型
  2. 邮件营销解密:为什么一些品牌比你更幸运?
  3. MySql数据库相关小知识
  4. 【6月比赛合集】103场可报名的数据挖掘大奖赛,任君挑选!
  5. 金融期货开户有什么用(期货开户支持哪些银行)
  6. java 气泡聊天消息_Html,CSS 实现类似QQ的气泡聊天
  7. 用C语言求n以内的素数
  8. 人力资源管理专业知识与实务(初级)【13】
  9. ccf-csp 2018春季真题题解
  10. 云豹直播系统源码接入华为云存储,含问题及解决方法