用户登录  |  用户注册
首 页商业源码原创产品编程论坛
当前位置:PB创新网文章中心编程技巧Visual C++

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

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-03-16 20:30:57

作者: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.


Tags:

作者:佚名

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
PB创新网ourmis.com】Copyright © 2000-2009 . All Rights Reserved .
页面执行时间:11,781.25000 毫秒
Email:ourmis@126.com QQ:2322888 蜀ICP备05006790号