分享
 
 
 

Guru of the week:#17 类型映射.

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

作者:Hub Sutter

译者:黄森堂

/*此文是译者出于自娱翻译的GotW(Guru of the Week)系列文章的一篇,原文的版权是属于Hub Sutter(著名的C++专家,《Exceptional C++》的作者)。此文的翻译没有征得原作者的同意,只供学习讨论。——译者:黄森堂*/

#17 类型映射.

难度:6/10

你知道C++的类型映射吗?,在你的代码中使用它们来提高可靠性。

问题:

比旧的C的类型映射,在标准C++中新的类型映射提供了更多的安全与存取能力,你知道它们吗?,剩下的问题就是如何使用它们:

class A { /*...*/ };

class B : virtual A { /*...*/ };

struct C : A { /*...*/ };

struct D : B, C { /*...*/ };

A a1; B b1; C c1; D d1;

const A a2;

const A& ra1 = a1;

const A& ra2 = a2;

char c;

1.以下新的类型映射没有同等的C的类型映射吗?

const_cast

dynamic_cast

reinterpret_cast

static_cast

2.以下的每一个C的类型映射中,用同等的新的类型映射来写,如果不用新的类型映射来写,它们是错的吗?

void f() {

A* pa; B* pb; C* pc;

pa = (A*)&ra1;

pa = (A*)&a2;

pb = (B*)&c1;

pc = (C*)&d1;

}

3.评价以下C++类型映射后的类型与正确性。

void g() {

unsigned char* puc = static_cast<unsigned char*>(&c);

signed char* psc = static_cast<signed char*>(&c);

void* pv = static_cast<void*>(&b1);

B* pb1 = static_cast<B*>(pv);

B* pb2 = static_cast<B*>(&b1);

A* pa1 = const_cast<A*>(&ra1);

A* pa2 = const_cast<A*>(&ra2);

B* pb3 = dynamic_cast<B*>(&c1);

A* pa3 = dynamic_cast<A*>(&b1);

B* pb4 = static_cast<B*>(&d1);

D* pd = static_cast<D*>(pb4);

pa1 = dynamic_cast<A*>(pb2);

pa1 = dynamic_cast<A*>(pb4);

C* pc1 = dynamic_cast<C*>(pb4);

C& rc1 = dynamic_cast<C&>(*pb2);

}

解决方法:

比旧的C的类型映射,在标准C++中新的类型映射提供了更多的安全与存取能力,你知道它们吗?,剩下的问题就是如何使用它们:

class A { /*...*/ };

class B : virtual A { /*...*/ };

struct C : A { /*...*/ };

struct D : B, C { /*...*/ };

A a1; B b1; C c1; D d1;

const A a2;

const A& ra1 = a1;

const A& ra2 = a2;

char c;

1.以下新的类型映射有同等的C的类型映射吗?

只有dynamic_cast没用同等的C的类型映射,所有其它的新的类型映射都有相应的旧的类型映射。

2.以下的每一个C的类型映射中,用同等的新的类型映射来写,如果不用新的类型映射来写,它们是错的吗?

void f() {

A* pa; B* pb; C* pc;

pa = (A*)&ra1;

使用 const_cast: pa = const_cast<A*>(&ra1);

pa = (A*)&a2;

这是错误的表达式,没有同等新的类型映射,const_cast是替代者,但因为a2是const对象,结果不明确。

pb = (B*)&c1;

使用 reinterpret_cast: pb = reinterpret_cast<B*>(&c1);

pc = (C*)&d1;

}

上面的类型映射在C是错误的,在C++里,没有映射需要:pc = &d1;

3.评价以下C++类型映射后的类型与正确性。

开始,先声明:我们不知道这些类任何一个是否有虚函数,如果这类不包含虚函数的话,以下所有dynamic_case全是错的,剩下的讨论部分,我们假定所有类都有虚函数,让使用dynamic_cast是合法的,

void g() {

unsigned char* puc = static_cast<unsigned char*>(&c);

signed char* psc = static_cast<signed char*>(&c);

错误:对以上两行我们必须使用reinterpret_cast,这个首先让你感到惊奇的,但理由是char,singed char与unsigned char是三个不同的类型,在它们之中任何通过对它们进行明确的转换都是没有相联的,所以指向无关的的对象,

void* pv = static_cast<void*>(&b1);

B* pb1 = static_cast<B*>(pv);

两者之间是有细微的地方,但前者不是必须的,因为它总是明确地从对象指针向void*指针进行转换。

B* pb2 = static_cast<B*>(&b1);

这儿有细微的地方,但不必要的,因为参数已经是B*.

This is fine, but unnecessary since the argument is already a B*.

A* pa1 = const_cast<A*>(&ra1);

这是合法的,但映射成const是通常缺少类型才进行的,大部分的情况下,在哪儿移去指针的const或引用相关到类型成员与关键字的掩盖是合法的,在GotW #6有更多的关于const的正确用法

A* pa2 = const_cast<A*>(&ra2);

错误:如果指针在对象里使用写将产生不确定的行为,原因a2实际上上是const对象,为什么呢?,思考编译器是允许a2创建同样的const对象与使用它的信息存储在只读内存中并作最佳化,

注释:我没有给出使用const_cast转换成非const指向const指针的示例,理由是这是多余的,它早已是合法的分配非const指针指向const指针,我们只需要const_cast 去做相反的事。

B* pb3 = dynamic_cast<B*>(&c1);

错误(如果你尝试使用pb3):因为c1不是A B(原因:C不是起源于B,在实际上它也不完全起源于B),它将pb3设为NULL,唯一正确的类型映射是使用reinterpret_cast,而且使用它始终是不幸的。

A* pa3 = dynamic_cast<A*>(&b1);

错误:因为b1不是A A(原因:B不是起源于A,但它起源是虚基类A(也就是说从虚基类派生的都不能转换成该基类的类型)),这是非法的。

B* pb4 = static_cast<B*>(&d1);

这儿有细微的地方,因为源于基类的指针转换是不需要明确声明所以不需要。

D* pd = static_cast<D*>(pb4);

这儿有细微的地方,如果你预期这儿需要dynamic_cast的话是你会吃惊的。理由是当目标是已知道的时候,向下映射是静态的,但要小心:你是说编译器在事实上知道你的,它为什么开始指向实际上的它的类型,如果你错了,那么类型映射就不能通知你有问题(像dynamic_cast一样,如果类型映射失败它将返回空指针),且最多你能取得非真实的运行时错误与程序崩溃。

pa1 = dynamic_cast<A*>(pb2);

pa1 = dynamic_cast<A*>(pb4);

这儿有两个看起来很相似,它们都尝试使用dynamic_cast把B*转换成A*,然而,第一个是错误的而第二个是对的。

这儿有个理由:同上面的注释,你不能使用dynamic_cast去映射指向实际上是B对象(pb2是指向b1对象)成A对象,因为B是从A进行私有继承,非公有继承,然而,第二个映射成功是因为pb4指向对象d1,且d像A一样是间接派生于基类(通过C),与dynamic_cast是允许映射越过继承体系,使用这种路径B* -> D* -> C* -> A*.

C* pc1 = dynamic_cast<C*>(pb4);

这儿有两个很细微,与前面的理由一样:dynamic_cast通过继承体系进行映射,所以这是合法且执行成功。

C& rc1 = dynamic_cast<C&>(*pb2);

}

最后,这而也有细微的地方...,因为*pb2不是实际上上的a C,dynamic_cast将执出bad_cast异常失败信号。为什么呢?如果映射失败,dynamic_cast将返null,但这儿引用的对象是空的,如果引用失败那它不能返回空的引用,这儿除了抛出异常外没有失败的信号发送到客户端,所以那儿为什么只有bad_cast异常。

一些个人看法:

1.cber:dynamic_cast用于继承体系结构的转型(向下是自动的,向上需要验证),较为安全(不过需要是polymorphic classes)static_cast有点类似于C中的强制转型。具体的可以看看MEC Item2

2.dragonznz:One for compile time, one for runtime. I think.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有