C++中的四种转型操作符

在详细介绍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++中的四种转型操作符,布布扣,bubuko.com

时间: 2024-11-02 23:31:41

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

C++四种cast操作符

C++的四种cast操作符的区别发信站: 水木社区 (Thu Jan 26 21:15:16 2006), 站内 声明 by NetMD:并非我的原创,来自互联网,且是两篇帖子的合集,个人觉得这样才比较完备 ---------------------------------------------------------------------- Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么?为什么要注意? A

c++四种类型转换操作符简要总结

1.  static_cast<target>(expression) 可用于存在继承关系的类指针/引用之间的向上向下转换.执行向下转换时没有安全检查(区别于dynamic_cast),所以如果实际类型与目标类型不符合,编译虽然可以通过,但运行时的后果未定义. void*指针转换为实际的指针 其他基本类型的隐式转换以及反方向的转换,如:int <-> double 2.  dynamic_cast<target>(expression) 只能用于target为类指针或者

Activity中的四种启动模式

在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. Android总Activity的启动模式分为四种: [html] view plaincopy Activity启动模式设置: <activity android:name=".MainActivity" android:launchMode="standard" 

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

简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用)的作用.同时我们还将介绍ReferenceQueue和WeakHashMap的功能和使用示例. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. JAVA中的四种引用 四种引用中,软引用.若引用.虚引用都需要相关类来创建.创建的时候

java中的四种单例实现方式

在java中,单例设计模式是非常常见的设计模式,对单例设计模式的概念,不做过多的介绍,下面将逐一介绍四种单例设计模式: 1.第一种单例设计模式 1.1 代码实现 package com.singleton.one; /**  * 第一种单例设计模式  * @author Administrator  *  */ public class SingleTonOne { // 实例化 private static SingleTonOne instance = new SingleTonOne();

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

对称加密和分组加密中的四种模式(ECB.CBC.CFB.OFB) 一. AES对称加密: AES加密 分组 二. 分组密码的填充 分组密码的填充 e.g.: PKCS#5填充方式 三. 流密码:   四. 分组密码加密中的四种模式: 3.1 ECB模式 优点: 1.简单: 2.有利于并行计算: 3.误差不会被传送: 缺点: 1.不能隐藏明文的模式: 2.可能对明文进行主动攻击: 3.2 CBC模式: 优点: 1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL.IPSec的标准.

Spring(七)Spring中的四种增强和顾问

Spring中的四种增强有那四种? 前置增强    后置增强  环绕增强  异常增强 先编写接口和实体类  ISomeService和SomeServiceImpl package demo10; /** * Created by mycom on 2018/3/8. */ public interface ISomeService { public void doSome(); } package demo10; /** * Created by mycom on 2018/3/8. */ p

MySQL数据库中的四种隔离级别

原文:MySQL数据库中的四种隔离级别 事务的隔离性比想象的要复杂,在 SQL 标准中定义了四种级别的隔离级别.通常而言,较低级别的隔离通常可以执行更高的并发,系统的开销也更低 READ UNCOMMITTED 该级别为未提交读.在该级别中,事务中的修改即使没有提交,对其他事务也都是可见的.事务可以读取未提交的数据,这也被称为脏读.这个级别会导致很多的问题,从性能上来说,它不会比其他级别好太多,但缺乏其他级别的很多好处.除非真的有非常必要的理由,在实际应用中一般很少使用. READ COMMIT

C++的四种cast操作符的区别--类型转换

Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么?为什么要注意? A:转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式.为了类型转换一个简单对象为另一个对象你会使用传统的类型转换操作符.比如,为了转换一个类型为doubole的浮点数的指针到整型:代码:int i;double d; i = (int) d;或者: i = int (d); 对于具有标准定义转换的简单类型而言工作的很好.然而,这样