staticcast dynamiccast reinterpretcast constcast区别比较.docx

上传人:b****5 文档编号:11786043 上传时间:2023-04-01 格式:DOCX 页数:13 大小:52.36KB
下载 相关 举报
staticcast dynamiccast reinterpretcast constcast区别比较.docx_第1页
第1页 / 共13页
staticcast dynamiccast reinterpretcast constcast区别比较.docx_第2页
第2页 / 共13页
staticcast dynamiccast reinterpretcast constcast区别比较.docx_第3页
第3页 / 共13页
staticcast dynamiccast reinterpretcast constcast区别比较.docx_第4页
第4页 / 共13页
staticcast dynamiccast reinterpretcast constcast区别比较.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

staticcast dynamiccast reinterpretcast constcast区别比较.docx

《staticcast dynamiccast reinterpretcast constcast区别比较.docx》由会员分享,可在线阅读,更多相关《staticcast dynamiccast reinterpretcast constcast区别比较.docx(13页珍藏版)》请在冰豆网上搜索。

staticcast dynamiccast reinterpretcast constcast区别比较.docx

staticcastdynamiccastreinterpretcastconstcast区别比较

static_cast,dynamic_cast,reinterpret_cast,const_cast区别比较

 

隐式转换(implicitconversion)

shorta=2000;

intb;

b=a;

short是两字节,int是四字节,由short型转成int型是宽化转换(bit位数增多),编译器没有warning,如下图所示。

宽化转换(如char到int,int到longlong,int到float,float到double,int到double等)构成隐式转换,编译器允许直接转换。

但若反过来

doublea=2000;

shortb;

b=a;

此时,是从8字节的double型转成2字节的short型变量,是窄化转换,编译器就会有warning了,如下所示,提醒程序员可能丢失数据。

不过需要注意的是,有些隐式转换,编译器可能并不给出warning,比如int到short,但数据溢出却依然会发生。

 

C风格显式转换(Cstyleexplicitconversion)

 

要去掉上述waring很简单,熟悉C语言的程序员知道,有两种简单的写法(C风格转换与函数风格转换):

doublea=2000.3;

shortb;

b=(short)a;   //c-likecastnotation

b=short(a);   //functionalnotation 

如下图所示,此时warning就没了

这种显式转换方式简单直观,但并不安全,举一个父类和子类的例子如下:

1//classtype-casting

2#include

3usingnamespacestd;

4

5classCDummy{

6floati,j;

7CDummy():

i(100),j(10){}

8};

9

10classCAddition:

publicCDummy

11{

12int*x,y;

13public:

14CAddition(inta,intb){x=&a;y=b;}

15intresult(){return*x+y;}

16};

17

18intmain(){

19CDummyd;

20CAddition*padd;

21padd=(CAddition*)&d;

22cout<result();

23return0;

24}

编译器不报任何错,但运行结果出错,如下图所示:

究其原因,注意这一句:

padd=(CAddition*)&d;

此时父类的指针&d被C风格转换方式强制转成了子类的指针了,后面调用了子类的方法result,需要访问*x,但指针指向的对象本质还是父类的,所以x相当于父类中的i,y相当于父类中的j,*x相当于*i,但i是float型变量(初始化为100),不是地址,所以出错,如果程序员正是鲁莽地对这个地址指向的内存进行写入操作,那将可能会破坏系统程序,导致操作系统崩溃!

这里有一个重要概念,CAddition*是子类的指针,它的变量padd可以调用子类的方法,但是它指向的是父类的对象,也就是说padd指向的内存空间里存放的是父类的成员变量。

深入地说,数据在内存中是没有“类型”一说的,比如0x3F可能是字符型,也可能是整型的一部分,还可能是地址的一部分。

我们定义的变量类型,其实就是定义了数据应该“被看成什么”的方式。

因此padd类指针实质是定义了取值的方式,如padd->x就是一并取出内存空间里的0号单元至3号单元的值(共4个字节),将其拼成32位并当作指针,padd->y则取出内存空间里的4号单元至7号单元(共4个字节),将其拼成32位并当作int型变量。

但实际上padd指向的是父类的对象,也就是前4个字节是float型变量,后4个字节也是float型变量。

从这里可以看出,程序员的这种转换使编译器“理解”出错,把牛当成马了。

从上可见,用C风格的转换其实是不安全的,编译器无法看到转换的不安全。

 

上行转换(up-casting)与下行转换(down-casting)

 

看到这个,读者可能会问,哪些转换不安全?

根据前面所举的例子,可以看到,不安全来源于两个方面:

其一是类型的窄化转化,会导致数据位数的丢失;其二是在类继承链中,将父类对象的地址(指针)强制转化成子类的地址(指针),这就是所谓的下行转换。

“下”表示沿着继承链向下走(向子类的方向走)。

类似地,上行转换的“上”表示沿继承链向上走(向父类的方向走)。

我们给出结论,上行转换一般是安全的,下行转换很可能是不安全的。

为什么呢?

因为子类中包含父类,所以上行转换(只能调用父类的方法,引用父类的成员变量)一般是安全的。

但父类中却没有子类的任何信息,而下行转换会调用到子类的方法、引用子类的成员变量,这些父类都没有,所以很容易“指鹿为马”或者干脆指向不存在的内存空间。

值得一说的是,不安全的转换不一定会导致程序出错,比如一些窄化转换在很多场合都会被频繁地使用,前提是程序员足够小心以防止数据溢出;下行转换关键看其“本质”是什么,比如一个父类指针指向子类,再将这个父类指针转成子类指针,这种下行转换就不会有问题。

 

针对类指针的问题,C++特别设计了更加细致的转换方法,分别有:

static_cast(expression)

dynamic_cast(expression)

reinterpret_cast(expression)

const_cast(expression)

可以提升转换的安全性。

 

static_cast(expression)静态转换

 

静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。

比如:

doubled=3.14159265;

inti=static_cast(d);

 

但static_cast已经有安全性的考虑了,比如对于不相关类指针之间的转换。

参见下面的例子:

1//classtype-casting

2#include

3usingnamespacestd;

4

5classCDummy{

6floati,j;

7};

8

9classCAddition{

10intx,y;

11public:

12CAddition(inta,intb){x=a;y=b;}

13intresult(){returnx+y;}

14};

15

16intmain(){

17CDummyd;

18CAddition*padd;

19padd=(CAddition*)&d;

20cout<result();

21return0;

22}

这个例子与之前举的例子很像,只是CAddition与CDummy类没有任何关系了,但main()中C风格的转换仍是允许的padd=(CAddition*)&d,这样的转换没有安全性可言。

 

如果在main()中使用static_cast,像这样:

1intmain(){

2CDummyd;

3CAddition*padd;

4padd=static_cast(&d);

5cout<result();

6return0;

7}

 

编译器就能看到这种不相关类指针转换的不安全,报出如下图所示的错误:

注意这时不是以warning形式给出的,而直接是不可通过编译的error。

从提示信息里可以看到,编译器说如果需要这种强制转换,要使用reinterpret_cast(稍候会说)或者C风格的两种转换。

总结一下:

static_cast最接近于C风格转换了,但在无关类的类指针之间转换上,有安全性的提升。

 

dynamic_cast(expression)动态转换

 

动态转换确保类指针的转换是合适完整的,它有两个重要的约束条件,其一是要求new_type为指针或引用,其二是下行转换时要求基类是多态的(基类中包含至少一个虚函数)。

看一下下面的例子:

1#include

2usingnamespacestd;

3classCBase{};

4classCDerived:

publicCBase{};

5

6intmain()

7{

8CBaseb;CBase*pb;

9CDerivedd;CDerived*pd;

10

11pb=dynamic_cast(&d);//ok:

derived-to-base

12pd=dynamic_cast(&b);//wrong:

base-to-derived

13}

在最后一行代码有问题,编译器给的错误提示如下图所示:

把类的定义改成:

classCBase{virtualvoiddummy(){}};

classCDerived:

publicCBase{};

再编译,结果如下图所示:

编译都可以顺利通过了。

这里我们在main函数的最后添加两句话:

cout<

cout<

输出pb和pd的指针值,结果如下:

我们看到一个奇怪的现象,将父类经过dynamic_cast转成子类的指针竟然是空指针!

这正是dynamic_cast提升安全性的功能,dynamic_cast可以识别出不安全的下行转换,但并不抛出异常,而是将转换的结果设置成null(空指针)。

再举一个例子:

1#include

2#include

3usingnamespacestd;

4

5classCBase{virtualvoiddummy(){}};

6classCDerived:

publicCBase{inta;};

7

8intmain(){

9try{

10CBase*pba=newCDerived;

11CBase*pbb=newCBase;

12CDerived*pd;

13

14pd=dynamic_cast(pba);

15if(pd==0)cout<<"Nullpointeronfirsttype-cast"<

16

17pd=dynamic_cast(pbb);

18if(pd==0)cout<<"Nullpointeronsecondtype-cast"<

19

20}catch(exception&e){cout<<"Exception:

"<

21return0;

22}

输出结果是:

Nullpointeronsecondtype-cast

两个dynamic_cast都是下行转换,第一个转换是安全的,因为指向对象的本质是子类,转换的结果使子类指针指向子类,天经地义;第二个转换是不安全的,因为指向对象的本质是父类,“指鹿为马”或指向不存在的空间很可能发生!

最后补充一个特殊情况,当待转换指针是void*或者转换目标指针是void*时,dynamic_cast总是认为是安全的,举个例子:

1#include

2usingnamespacestd;

3classA{virtualvoidf(){}};

4classB{virtualvoidf(){}};

5

6intmain(){

7A*pa=newA;

8B*pb=newB;

9void*pv=dynamic_cast(pa);

10cout<

11//pvnowpointstoanobjectoftypeA

12

13pv=dynamic_cast(pb);

14cout<

15//pvnowpointstoanobjectoftypeB

16}

运行结果如下:

可见dynamic_cast认为空指针的转换安全的,但这里类A和类B必须是多态的,包含虚函数,若不是,则会编译报错。

 

reinterpret_cast(expression)重解释转换

 

这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现,举个例子:

classA{};

classB{};

A*a=newA;

B*b=reinterpret_cast(a);//correct!

更厉害的是,reinterpret_cast可以把整型数转换成地址(指针),这种转换在系统底层的操作,有极强的平台依赖性,移植性不好。

它同样要求new_type是指针或引用,下面的例子是通不过编译的:

doublea=2000.3;

shortb;

b=reinterpret_cast(a);//compileerror!

 

const_cast(expression) 常量向非常量转换

这个转换好理解,可以将常量转成非常量。

1//const_cast

2#include

3usingnamespacestd;

4

5voidprint(char*str)

6{

7cout<

8}

9

10intmain(){

11constchar*c="sampletext";

12char*cc=const_cast(c);

13Print(cc);

14return0;

15}

从char*cc=const_cast(c)可以看出了这个转换的作用了,但切记,这个转换并不转换原常量本身,即c还是常量,只是它返回的结果cc是非常量了。

 

 

总结

C风格转换是“万能的转换”,但需要程序员把握转换的安全性,编译器无能为力;static_cast最接近于C风格转换,但在无关类指针转换时,编译器会报错,提升了安全性;dynamic_cast要求转换类型必须是指针或引用,且在下行转换时要求基类是多态的,如果发现下行转换不安全,dynamic_cast返回一个null指针,dynamic_cast总是认为void*之间的转换是安全的;reinterpret_cast可以对无关类指针进行转换,甚至可以直接将整型值转成指针,这种转换是底层的,有较强的平台依赖性,可移植性差;const_cast可以将常量转成非常量,但不会破坏原常量的const属性,只是返回一个去掉const的变量

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1