C++异常处理和RTTI技术 20130930

1.异常处理的基本知识

C语言中是没有内置运行时错误处理机制,对于错误发生的时候使用的几种处理机制:

函数返回彼此协商后统一定义的状态编码来表示操作成功、失败或者是其他类型的错误;使用全局变量来保存错误编码,每一个使用到他的函数在开始的时候都会检查他的值,并且每一个函数的操作结果都会写到这个全局变量中,如使用errno表示任何一个函数调用返回后产生的错误码;出错的时候终止程序的运行。

但是这些传统的方法村下载一些问题:没有形成统一的标准;将正常的代码和错误处理程序紧紧的绑定在一起;有些函数式咩有返回值的;全局的错误变量,不仅在函数的开头检查它,而且有时候还要把他清零;发生错误的时候,使用exit或者abort粗暴的退出程序是很不友好的方式。

C++中的解决办法就是:C++异常处理机制。允许从异常抛出点把任意数量的信息已类型安全的方式传递给异常处理器;对于没有抛出异常的代码段,他不会带来任何的二外的时间和空间开销;保证程序抛出的任何一个异常都能够被适当的处理器捕获;通过一种组合方式可以是程序员写出处理一组异常的处理器;能够直接使用在多线程程序中。。。

2.异常处理C++

在C++中如果一个异常在抛出点没有被处理的话,那么他会一直被抛向上层的调用者,直到Main函数遇到一个可以处理该异常的处理器,否则就会调用terminate()函数技术程序。

异常类型和异常对象:任何一种类型都是可以当做异常类型,包括基本的数据类型的变量常量,任何类型的指针等等。但是我们一般不会直接使用基本数据类型的对象作为异常,因为这就退回到最开始处理异常的地步。

异常处理是一种程序控制结构,它包括4个组成部分:抛出异常、提炼异常、捕获异常、异常对象本身。C++异常处理的关键字 throw try{} catch{}. 异常抛出点和异常捕获点距离肯呢过会很远,异常抛出点可能深埋在底层软件模块内,而异常捕获点常常在高层组价中;异常捕获却必须和异常提炼块结合使用,并且可以通过异常组合在一个地点捕获多种异常。

异常的匹配规则:必须保存每一个throw语句抛出的异常对象的类型信息和每一个catch子句的参数类型信息,其目的就是在运行的时候执行异常对象和异常处理器的类型匹配。

当异常抛出时局部对象如何释放:throw语句就像一个goto语句,因此他本质上是一种程序控制手法,在正常的情况下每一个函数在结束前的一刻都会调用其创建在堆栈中的每一个对象的析构函数来释放其占用的资源。但是当函数执行遇到异常抛出的时候,妖魔进入当前函数的一个catch快,要么将异常传递给上层调用者,同时当前的函数结束,函数内部的局部对象如何处理?

引入Resource Acquisition is initialization思想,在初始化阶段请求资源,对象销毁的时候释放资源。在构造函数中申请资源(内存、文件、通信设备等等),在析构函数中释放资源。

异常处理机制保证:所有从try到throw语句之间构造的局部对象的析构函数将被自动调用,然后清退堆栈的内容,一直上溯到main函数。

如果无法判断异常的类型则我么可以使用catch(void*) 处理那些不知道是什么类型的异常,但是要放倒最后面,否则所有的异常都会被它处理掉。

3.虚函数面临的问题

在介绍RTTI之前,首先了解一下虚函数的不足:

一般来说虚成员函数可以满足对象的动态类型匹配的需要。一个定义良好的类层次结构应该为基类中声明的每一个虚成员函数定义有意义的操作。但是对于公共类型的接口对于不同的子类可能不适用。这里我们便需要RTTI(运行时类型信息)的地方

4.RTTI以及其构成

异常操作不是在编译的时候匹配好的,而是在运行的时候才会执行具体类型匹配操作。所以这里需要的是在运行期间检查每一个对象类型的信息的手段。一个异常类型可能是多态类型,当抛出的异常对象为派生了对象的时候,如果找不到确定的处理过程就应该尝试匹配其基类的处理过程,这也在运行的时候检查一个对象的类型信息。这也需要RTTI机制

如果支持运行时对一个对象确切类型的检索,就需要改变对象内存映像,比如插入一个指针类指向器类型信息。虚拟机制出现之后,类型信息放在vtable中;RTTI技术不仅需要额外的内存开销(为每一个类型增加一个type_info对象),而且在运行的时候检索对象的类型信息需要一定的时间开销;在多数情况下,虚函数的功能对于运行时对象的匹配已经足够了。

但是在C++中支持多种继承,静态的类型检查和动态函数的绑定不能够满足正确的判断所以RTTI和type_info被加入到C++中。

为了能够在运行的时候获得对象的类型信息type_info,C++增加了两个运算符:typeid 和dynamic_cast<>, type_info常用的三个成员函数: operator==() operator!=() 和 name()。

typeid运算符:就像sizeof一样是C++语言直接支持的,它对一个对象或者类型名作为参数,返回一个匹配 const type_info对象,表明对象的确切类型。

typeid(object) == typeid(Television)

另外static_cast<>的用途:强制的类型转换。

dynamic_cast<dest_type>(src);这样的话如果双src和dest_type之间有关系,则可以转换,否则转换失败。

dynamic_cast<>可以用来转换指针和引用,但是不能转换对象,如果转换的目标类型是指针,如果转换失败则返回NULL指针;但是如果是引用则会抛出异常std::bad_cast,因为不存在NULL的引用。

另外dynamic_cast<>是通过该对象的vptr检查位于类型的vtable中的第一个solt的type_info,因此dynamic_cast只能够用于多态类型的对象,否则检出限编译错误。

C++复习8.异常处理和RTTI的更多相关文章

  1. C异常处理和C++异常处理的对比

    每一种编译器实现异常处理的方式会有所不同,但是都是基于Windows的SEH异常处理.这里以MSC编译器为例. C异常处理 #include <Windows.h> int main(in ...

  2. python之异常处理和re模块补充

    一.re模块的补充 1.从一个字符串中获取要匹配的内容 findall:返回一个列表 2.search ***** 验证用户输入内容 '^正则规则$':返回一个对象,用group()取值 3.matc ...

  3. 进击的Python【第七章】:python各种类,反射,异常处理和socket基础

    Python的高级应用(三)面向对象编程进阶 本章学习要点: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 一.面向对象高级语法部分 静态方法 ...

  4. 异常处理和JDBC

    1.异常: 格式:try{ 要执行的可能出现异常的语句 } catch(Exception e){ 对异常进行处理的语句 }    finally{    一定会被处理的语句 //可以不写 } 当需要 ...

  5. 异常处理和Throwable中的几个方法

    package cn.lijun.demo; /* * try { //需要被检测的语句. } catch(异常类 变量) { //参数. //异常的处理语句. } finally { //一定会被执 ...

  6. python基础之 异常处理和logging模块

    1.异常处理 l = ['apple','admin','kobe'] for id,item in enumerate(l,1): print(id,item) try: choose_id = i ...

  7. Python之异常处理和socket套接字连接7

    一.异常处理 1)异常处理的使用意义 什么是异常处理 异常是程序发生错误的信号,即程序一旦出错就会立刻产生一个异常,如果该异常没有被处理 那么异常就抛出来,程序的运行也随之终止 异常分为三部分: 异常 ...

  8. vb.net结构化异常处理和“邪用”

    vb.net中的错误处理包括两种:非结构化异常处理技术和结构化异常处理.非结构化异常处理技术在vb 6.0中使用的比较普遍,即通过Err对象和ON Error.Go To.Resume等语句来实现.这 ...

  9. Java第六次作业--异常处理和Java类集

    Deadline: 2017-5-4 23:00 一.学习要点 认真看书并查阅相关资料,掌握以下内容: 理解Java的异常处理机制 掌握捕获异常和声明抛出异常的方法 掌握List接口的实现类Array ...

随机推荐

  1. intellij-idea+maven搭建scala环境

    一 . 安装JDK 1. 下载地址: http://download.oracle.com/otn-pub/java/jdk/8u181-b13/96a7b8442fe848ef90c96a2fad6 ...

  2. java中数组以及集合

    java中数组: 数组在Java里是一种特殊类型,有别于普通的“类的实例”的对象.但实际数组也是一种对象类型,int[]a = new int[5]  a是在java栈中分配的引用变量,类型是int[ ...

  3. 前端学习笔记之ES6快速入门

    0x1 let和const let ES6新增了let命令,用于声明变量.其用法类似var,但是声明的变量只在let命令所在的代码块内有效. { let x = 10; var y = 20; } x ...

  4. 关于HttpRuntime.Cache的运用

    存Cache方法: HttpRuntime.Cache.Add( KeyName,//缓存名 KeyValue,//要缓存的对象 Dependencies,//依赖项 AbsoluteExpirati ...

  5. RESTful风格与RESTful Api

    REST(representational state transfer)(表述性状态转移),词汇解析: 1.representational 表述性:指资源以用各种形式来表述,包括 XML.JSON ...

  6. [转]C语言 gets()和scanf()函数的区别

    scanf( )函数和gets( )函数都可用于输入字符串,但在功能上有区别.若想从键盘上输入字符串"hi hello",则应该使用__gets__函数. gets可以接收空格:而 ...

  7. Redis-数据操作

    数据操作 redis是key-value的数据,所以每个数据都是一个键值对 键的类型是字符串 值的类型分为五种: 字符串string 哈希hash 列表list 集合set 有序集合zset 数据操作 ...

  8. shell小脚本--从laod博客更新hosts文件

    #!/bin/bash #-------------------------------------------- # name: change-hosts.sh #----------------- ...

  9. linux之磁盘配额(quota)使用方法(转)

    1.什么是quota 简单的说就是限制用户对磁盘空间的使用量. 因为Linux是多用户多任务的操作系统,许多人共用磁盘空间,为了合理的分配磁盘空间,于是就有了quota的出现. 2.quota的用途  ...

  10. 连续取模-function

    2017-09-22 21:56:08 The shorter, the simpler. With this problem, you should be convinced of this tru ...