在具体介绍C++中的四种转型操作符之前,我们先来说说旧式转型的缺点:

①它差点儿同意将不论什么类型转换为不论什么其它类型,这是十分拙劣的。假设每次转型都可以更精确地指明意图,则更好。

②旧式转型难以辨识。旧式转型的语法结构是由一对小括号加上一个对象名称组成。而小括号和对象名称在C++的不论什么地方都有可能被使用。

为解决C旧式转型的缺点,C++导入了4个新的转型操作符:static_cast、const_cast、dynamic_cast、reinterpret_cast。

以下我来一一分析这四种转型操作符。

1)static_cast

static_cast基本上拥有与C旧式转型同样的威力与意义,以及同样的限制。

比如。不可以利用static_cast将一个struct转型为int。或将一个double转型为pointer;这些都是C旧式转型动作原本就不可以完毕的任务。

static_cast甚至不可以移除表达式的常量性。

int a,b;

...

double c = static_cast<double>(a)/b;

2)const_cast

const_cast用来改变表达式中的常量性(constness)或变易性(volatileness)。使用const_cast,便是对人类(以及编译器)强调,通过这个转型操作符,我们唯一想改变的是某物的常量性或变易性。

假设将const_cast应用于上述以为的用途。那么转型动作会被拒绝。以下看一个样例:

class Widget{...};

class SpecialWidget:public Widget {...};

void update(SpecialWidget* psw);

SpecialWidget sw;//sw是个non-const对象

const SpecialWidget& csw = sw;//csw却是一个代表sw的reference。并视之为一个const对象

update(&csw);//错误!

不能讲const SpecialWidget*传给一个须要SpecialWidget*的函数

update(const_cast<SpecialWidget*>(&csw));//可!

&csw的常量性被去除了。也因此,csw(亦即sw)在此函数中可被更改。

update((SpecialWidget*)&csw);//情况同上,但使用的是较难辨识的c旧式转型语法

Widget* pw = new SpecialWidget;

update(pw);//错误!pw的类型是Widget*,但update()须要的却是SpecialWidget*。

update(const_cast<SpecialWidgt*>(pw));//错误!const_cast仅仅能用来影响常量性或变易性,无法进行继承体系的向下转型动作。

3)dynamic_cast

①dynamic_cast用来运行继承体系中”安全地向下转型或跨系转型动作“。

也就是说你能够利用dynamic_cast。将”指向base class objects的pointers或references“转型为”指向derived(或sibling base)class objects的pointers或references“,并得知转型是否成功。

假设转型失败,会以一个null指针(当转型对象是指针)或一个exception(当转型对象是reference)表现出来:

Widget* pw;

...

update(dynamic_cast<SpecialWidget*>(pw));//非常好,传给update()一个指针,指向pw所指的SpecialWidget----假设pw真的指向这种东西。否则传过去的将是一个null指针

void updateViaRef(SpecialWidget& rsw);

updateViaRef(dynamic_cast<SpecialWidget&>(*pw));//非常好。传给updateViaRef()的是pw所指的SpecialWidget----假设pw真的指向这种东西;否则抛出一个exception

dynamic_cast仅仅能用来助你巡航于继承体系之下。它无法应用在缺乏虚函数的类型身上,也不能改变类型的常量性。

②dynamic_cast的第二个用途是找出被某对象占用的内存的起始点。比如:

class HeapTracked

{

public:

bool isOnheap() const;

private:

typedef const void* RawAddress;

static list<RawAddress> addresses;

};

bool HeapTracked::isOnheap() const

{

const void* rawAddress = dynamic_cast<const void*>(this);//取得一个指针,指向*this所占内存的起始处

list<RawAddress>::iterator it = find(addresses.begin(),addresses.end(),rawAddress);

return it != addresses.end();

}

凡涉及”多重继承或虚拟基类“的对象,会拥有多个地址,仅仅要简单地将指针”动态转型“为void*(或const void*或volatile void*或const volatile void*),便会获得一个指针,指向”原指针所指对象“的内存起始处。

只是,dynamic_cast仅仅适用于那种”所指对象至少有一个虚函数“的指针身上。

4)reinterpret_cast

这个操作符的转换结果差点儿总是与编译平台息息相关。所以reinterpret_cast不具移植性。

reinterpret_cast的最经常使用用途是转换”函数指针“类型。

如果有一个数组。存储的都是函数指针。有特定的类型:

typedef void (*FuncPtr)();//FuncPtr是个指针,指向某个函数。

FuncPtr funcPtrArray[10];//funcPtrArray是个数组,内有10个FuncPtrs。

如果因为某种原因,你希望将下面函数的一个指针放进funcPtrArray中:

int doSomething();

假设没有转型。不可能办到这一点,由于doSomething的类型与funcPtrArray所能接受的不同。

funcPtrArray内各函数指针所指函数的返回值是void,但doSomething的返回值却是int:

funPtrArray[0] = &doSomething;//错误!类型不正确

使用reinterpret_cast,能够强迫编译器了解你的意图。

funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);

函数指针的转型动作并不具有移植性(C++不保证全部的函数指针都能以此方式又一次呈现),某些情况下这种转型可能会导致不对的结果,所以应该尽量避免将函数指针转型。

假设编译器尚未支持这些新式转型动作,也能够使用传统转型方式代替static_cast、const_cast和reinterpret_cast。甚至能够利用宏来仿真这些新语法。

#define static_cast(TYPE,EXPR) ((TYPE)(EXPR))

#define const_cast(TYPE,EXPR) ((TYPE)(EXPR))

#define reinterpret_cast(TYPE,EXPR) ((TYPE)(EXPR))

至于dynamic_cast,也可回头使用旧式的C型语法。或者定义一个宏。可是它们不可能告诉你转型是否成功。

C++中的四种转型操作符的更多相关文章

  1. [转]C++四种cast操作符

    http://blog.csdn.net/starryheavens/article/details/4617637 C 风格(C-style)强制转型如下: (T) expression 或 T(e ...

  2. C++四种cast操作符

    C 风格(C-style)强制转型如下: (T) expression  或 T(expression) //函数风格(Function-style) 两种形式之间没有本质上的不同. 对于具有转换的简 ...

  3. 对称加密和分组加密中的四种模式(ECB、CBC、CFB、OFB)

    一. AES对称加密: AES加密 分组 二. 分组密码的填充 分组密码的填充 e.g.: PKCS#5填充方式 三. 流密码:   四. 分组密码加密中的四种模式: 3.1 ECB模式 优点: 1. ...

  4. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

  5. Activity中的四种启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  6. JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例

    简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...

  7. C语言_了解一下C语言中的四种存储类别

    C语言是一门通用计算机编程语言,应用广泛.C语言的设计目标是提供一种能以简易的方式编译.处理低级存储器.产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言. C语言中的四种存储类别:auto ...

  8. Java中的四种引用

    引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...

  9. JavaScript确定一个字符串是否包含在另一个字符串中的四种方法

    一.indexOf() 1.定义 indexOf()方法返回String对象第一次出现指定字符串的索引,若未找到指定值,返回-1.(数组同一个概念) 2.语法 str.indexOf(searchVa ...

随机推荐

  1. Python 常量与变量

    先在lib文件夹中定义一个模块 class _const(object): class ConstError(TypeError):pass def __setattr__(self, name, v ...

  2. 基于脚本的动画的计时控制(“requestAnimationFrame”)(转)

    requestAnimationFrame 方法的支持,该方法通过在系统准备好绘制动画帧时调用该帧,从而为创建动画网页提供了一种更平滑更高效的方法.在此 API 之前,使用 setTimeout 和  ...

  3. android studio 改变主题及字体大小

    一丶修改主题背景 1.点击图中的小扳子图标(设置),或者点击file->setting-> 2.找到Appearance->在Theme中选择Darcula,即可改变成当前最主流的主 ...

  4. windows下安装php笔记

    为了更深入的理解下服务端的配置 ,上篇文章讲了如何在windows下安装apache , 接下来再研究下在windows下安装php并且结合apache运行php环境, 纯属学习用 ^^ ,如果嫌麻烦 ...

  5. 工作流activiti-01个人小结

    最近公司需要开发工作流 使用的是activiti  个人拿着官方的User Guide 摸索了好几天 现做个小结: 对公司的小型OA开发一般用到如下几点: 1.依据客户业务得到业务流程图  可以是xm ...

  6. MySQL是否在扫描额外的记录

    在确定查询只是返回需要的数据之后,接下来应该看看查询为了返回结果是否扫描了过多的数据.对于MySQL,最简单的衡量查询开销的三个指标如下: 1响应时间,2扫描行数,3返回行数 没有那个指明能够完美的衡 ...

  7. 【结构型】Flyweight模式

    享元模式的主要目的.意图是为对象的大量使用提供一种共享机制.该模式的思想重在复用.共享复用.像文字.列表中的格子等这类多数都是需要考虑复用技术,否则必将大量耗费内存空间而使资源以及性能等大量耗费.该模 ...

  8. linux2.6.32 内核源码树解析与整理

    一 系统最核心组件目录: 1 arch目录该目录中的每个子目录中都与某种体系结构相对应,用于存放体系结构相关代码,向平台无关的系统核心模块提供所需的功能接口.每个体系结构对应的子目录下通常至少包含以下 ...

  9. Spring碎点知识

    1.依赖注入:不仅可以为Bean注入普通的属性值,还可以注入其他Bean的作用.通过配置文件组织在一起,这里的Bean是Java对象 说明:关于依赖注入与控制反转的这两个名字,表达的都是同一个意思,只 ...

  10. DOM 之通俗易懂讲解

    DOM是所有前端开发每天打交道的东西,但是随着jQuery等库的出现,大大简化了DOM操作,导致大家慢慢的“遗忘”了它的本来面貌.不过,要想深入学习前端知识,对DOM的了解是不可或缺的,所以本文力图系 ...