ITPub博客

首页 > 应用开发 > IT综合 > Guru of the week:#17 类型映射. (转)

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

原创 IT综合 作者:amyz 时间:2007-10-02 10:56:20 0 删除 编辑
Guru of the week:#17 类型映射. (转)[@more@]

作者: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(&c); signed char* psc = static_cast(&c); void* pv = static_cast(&b1); B* pb1 = static_cast(pv); B* pb2 = static_cast(&b1); A* pa1 = const_cast(&ra1); A* pa2 = const_cast(&ra2); B* pb3 = dynamic_cast(&c1); A* pa3 = dynamic_cast(&b1); B* pb4 = static_cast(&d1); D* pd = static_cast(pb4); pa1 = dynamic_cast(pb2); pa1 = dynamic_cast(pb4); C* pc1 = dynamic_cast(pb4); C& rc1 = dynamic_cast(*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(&ra1);

pa = (A*)&a2;


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

pb = (B*)&c1;


使用 reinterpret_cast: pb = reinterpret_cast(&c1);

pc = (C*)&d1; }


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

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

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

void g() { unsigned char* puc = static_cast(&c); signed char* psc = static_cast(&c);


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

void* pv = static_cast(&b1); B* pb1 = static_cast(pv);


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

B* pb2 = static_cast(&b1);


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

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

A* pa1 = const_cast(&ra1);


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

A* pa2 = const_cast(&ra2);


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

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

B* pb3 = dynamic_cast(&c1);


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

A* pa3 = dynamic_cast(&b1);


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

B* pb4 = static_cast(&d1);


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

D* pd = static_cast(pb4);


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

pa1 = dynamic_cast(pb2); pa1 = dynamic_cast(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(pb4);


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

C& rc1 = dynamic_cast(*pb2); }


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

一些个人看法

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

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


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752019/viewspace-974409/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    3982
  • 访问量
    7512788