C++转换符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 和 'const_cast'

来源:互联网 发布:数据建模工程师面试题 编辑:程序博客网 时间:2024/05/13 04:11

为什么要进行类型转换?

转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式。为了类型转换一个简单对象为另一个对象你会使用传统的类型转换操作符。

 Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么? 

C 风格(C-style)强制转型如下:
    (T) expression // 把表达式强制转换成T类型    

比如:

int i;
double d;
i
= (int) d;

函数风格(Function-style)强制转型使用这样的语法:
    T(expression) // cast expression to be of type T 

比如:

int i;
double d;
i
= int (d);

    这两种形式之间没有本质上的不同,它纯粹就是一个把括号放在哪的问题。对于具有标准定义转换的简单类型而言这个很好。毕竟是如此好写,然而,这样的转换符也能不分皂白的应用于类(class)和类的指针。貌似有点宽泛的转换,另外C风格的类型转换在程序语句中难以识别。在语法上,类型转换由圆括号和标识符组成,而这些可以用在C++中的任何地方。比如最简单的赋值,这就导致阅读代码的人也可能会忽略这种转换。

为了克服这些缺点,ANSI-C++标准定义了四个新的转换符:'reinterpret_cast', 'static_cast', 'dynamic_cast' 和 'const_cast',目的在于控制类(class)之间的类型转换。

代码:

reinterpret_cast<new_type>(expression)
dynamic_cast
<new_type>(expression)
static_cast
<new_type>(expression)
const_cast
<new_type>(expression)



1 reinterpret_cast

reinterpret_cast 是特意用于底层的强制转型,导致实现依赖(implementation-dependent)(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。
'reinterpret_cast'转换一个指针为其它类型的指针。它也允许从一个指针转换为整数类型。反之亦然。这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。'reinterpret_cast'就像传统的类型转换一样对待所有指针的类型转换。
如果情况是从一个指针到整型的拷贝,内容的解释是系统相关的,所以任何的实现都不是方便的。一个转换到足够大的整型能够包含它的指针是能够转换回有效的指针的。

应用实例:


代码:

class A {};
class B {};
A
* a = new A;
B
* b = reinterpret_cast<B *>(a);


2 static_cast
static_cast 可以被用于强制隐型转换(例如,non-const 对象转型为 const 对象,int 转型为 double,等等),它还可以用于很多这样的转换的反向转换(例如,void* 指针转型为有类型指针,基类指针转型为派生类指针),但是它不能将一个 const 对象转型为 non-const 对象(只有 const_cast 能做到),它最接近于C-style的转换
应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类。

在这例子里,被转换的父类没有被检查是否与目的类型相一致。
代码:
class Base {};
class Derived : public Base {};
Base
*a = new Base;
Derived
*b = static_cast<Derived *>(a);

'static_cast'除了操作类型指针,也能用于执行类型定义的显式的转换,以及基础类型之间的标准转换:

代码:
double d = 3.14159265;
int i = static_cast<int>(d);

3 dynamic_cast
dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。
'dynamic_cast'只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
代码:
复制代码
class Base { virtual dummy() {} };
class Derived : public Base {};

Base
* b1 = new Derived;
Base
* b2 = new Base;

Derived
* d1 = dynamic_cast<Derived *>(b1); // 成功
Derived* d2 = dynamic_cast<Derived *>(b2); // 失败: 返回 'NULL'
复制代码


如果一个引用类型执行了类型转换并且这个转换是不可能的,一个bad_cast的异常类型被抛出:
代码:
复制代码
class Base { virtual dummy() {} };
class Derived : public Base { };

Base
* b1 = new Derived;
Base
* b2 = new Base;

Derived d1
= dynamic_cast<Derived &*>(b1); //成功
Derived d2 = dynamic_cast<Derived &*>(b2); // 失败:异常抛出
复制代码


4 const_cast
const_cast 一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型。 
这个转换类型操纵传递对象的const属性,或者是设置或者是移除:
代码:
class C {};
const C *a = new C;
C
*b = const_cast<C *>(a);

其它三种操作符是不能修改一个对象的常量性的。
注意:'const_cast'也能改变一个类型的volatile限定符

关于volatile限定符:当一个对象的值可能会在编译器的控制或检测之外被改变时,例如一个被系统时钟更新的变量,那么对象应该声明成volatile。编译器执行的某些例行优化行为不能应用在已指定为volatile的对象上。volatile限定符的用法同const非常相似,都是作为类型的附加修饰符。volatile修饰符的主要目的是提示编译器,该对象的值可能在编译器未监测到的情况下被改变。因此编译器不能武断的对引用这些对象的代码作优化处理。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 吃不新鲜的虾怎么办 鸡胸肉不新鲜了怎么办 吃了不新鲜的鱼怎么办 生的猪肉有点臭怎么办? 猪肉馅不新鲜了怎么办 买的肉有点臭了怎么办 炸的东西不脆了怎么办 油炸东西回软了怎么办 吃石斑鱼蛋吐了怎么办 家里的烟筒堵了怎么办 脖子上长鸡皮肤怎么办 铁板烤蔬菜粘锅怎么办 残余尿量300ml怎么办 肌肉拉伤怎么办恢复快小腿 睡觉把背扭了怎么办 后背一侧扭筋了怎么办 背部的筋扭到了怎么办 跳绳跳得膝盖疼怎么办 跑步小腿变粗了怎么办 一蹲下膝盖就响怎么办 做深蹲时膝盖总是吱吱响怎么办 爬山爬的膝盖疼怎么办 膝盖一吹风就疼怎么办 走路太多膝盖腿疼怎么办 膝盖一着凉就痛怎么办 月子里脚受凉了怎么办 膝关节受凉少量积液发胀怎么办 刮痧后吹空调了怎么办 200斤胖子膝盖痛怎么办 风扇吹的腿疼怎么办 膝盖受凉但不疼怎么办 刮痧后洗了澡怎么办 刮痧后喝了啤酒怎么办 艾灸后吃水果了怎么办 刮痧后能洗澡了怎么办 膝盖筋扭了肿了怎么办 骑行之后膝盖疼怎么办 膝盖软骨磨没了怎么办 腿上膝盖长骨刺怎么办 打羽毛球后膝盖疼怎么办 打完羽毛球膝盖疼怎么办