zoukankan      html  css  js  c++  java
  • [Effective C++ --027]尽量少做转型动作

    引言                                                                                                                                                                                               

    C风格的转型动作

     (T)expression     // 将expression转型为T

    函数风格的转型动作看起来像这样

     T(expression)   // 将expression转型为T

    C++风格的四种转型

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

    第一节 C++各种转型的区别                                                                                                                                                           

    ・const_cast 一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型。 

    ・dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。
    ・reinterpret_cast 是特意用于底层的强制转型,导致实现依赖(implementation-dependent)(就是说,不可移植)的结果,例如,将一个指针转型为一个整数。这样的强制转型在底层代码以外应该极为罕见。

    ・static_cast 可以被用于强制隐型转换(例如,non-const 对象转型为 const 对象,int 转型为 double,等等),它还可以用于很多这样的转换的反向转换(例如,void* 指针转型为有类型指针,基类指针转型为派生类指针),但是它不能将一个 const 对象转型为 non-const 对象(只有 const_cast 能做到),它最接近于C-style的转换。

    区别:

    dynamic_cast可用于继承体系中的向下转型,即将基类指针转换为派生类指针,比static_cast更严格更安全。dynamic_cast在执行效率上比static_cast要差一些,但static_cast在更宽上范围内可以完成映射,这种不加限制的映射伴随着不安全性.static_cast覆盖的变换类型除类层次的静态导航以外,还包括无映射变换,窄化变换(这种变换会导致对象切片,丢失信息),用VOID*的强制变换,隐式类型变换等。

    reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它.我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的.(这句话是C++编程思想中的原话)

     static_cast 和 reinterpret_cast 操作符修改了操作数类型. 它们不是互逆的; static_cast 在编译时使用类型信息执行转换, 在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的. 另一方面, reinterpret_cast 仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。

    总结:

    1、static_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,反过来也支持,但会给出编译警告,它作用最类似C风格的“强制转换”,一般来说可认为它是安全的;

    2、dynamic_cast,支持父类指针到子类指针的转换,并根据实际情况调整指针的值,和static_cast不同,反过来它就不支持了,会导致编译错误,这种转换是最安全的转换;

    3、reinterpret_cast,支持任何转换,但仅仅是如它的名字所描述的那样“重解释”而已,不会对指针的值进行任何调整,用它完全可以做到“指鹿为马”,但很明显,它是最不安全的转换,使用它的时候,你得头脑清醒,知道自己在干什么;

    4、const_cast,这个转换能剥离一个对象的const属性,也就是说允许你对常量进行修改。

    第二节 转型的使用                                                                                                                                                                          

    假设我们有以下的代码

    1 class Base {...};
    2 class Derived: public Base {...};
    3 Derived d;
    4 Base* pb = &d;           // 隐喻的将Derived*转换为Base*

    在上述代码中,我们建立了一个base class指针指向派生类对象,但有时候上述的两个指针的值并不相同。这种情况下会有偏移量在运行期间被施与Derived指针上,用以取得正确的Base*指针值。

    这就表明,单一对象(比如派生类对象)可能拥有一个以上的地址(比如以Base*指向它时的地址和以Derived*指向它时的地址)。事实上,一旦发生多重继承,这事一直都在发生。

    需要注意的是:上面的偏移量是随着编译器不同而不同的。

    在调用基类的虚函数的时候,也很容易出现以下的问题:

    需求:在基类和派生类都定义了虚函数的时候,如果我们想要在派生类中调用父类的函数。

     1 class Base {
     2 public:
     3     virtual void onResize() {...};
     4 };
     5 
     6 class Device: public Base {
     7 public:
     8     virtual void onResize() {
     9         static_cast<Base>(*this).onResize();   // 调用基类的onResize函数,实际是不可行的
    10         ...
    11     }
    12 };

    在红色的代码中,*this转型为Base,调用Base::onResize。但是,它调用的并不是当前对象上的函数,而是稍早转型动作所建立的一个“*this对象的Base Class”的副本。

    改法很简单,拿掉转型,直接调用即可:

     1 class Base {
     2 public:
     3     virtual void onResize() {...};
     4 };
     5 
     6 class Device: public Base {
     7 public:
     8     virtual void onResize() {
     9         Base::onResize();   // 调用基类的onResize函数
    10         ...
    11     }
    12 };

    在这一节中,作者还讲述了两种避免转型的方法,其实原理都是一样的:直接调用,避免过多的转型!

    ◆总结                                                                                                                                                                                       

    1.如果可以,尽量避免转型,特别是在注重效率的代码中避免使用dynamic_cast

    2.如果必须要转型,请试着将其隐藏在某个函数背后

    3.宁可使用C++新型的转换,不用旧式转型

  • 相关阅读:
    10 个雷人的注释,就怕你不敢用!
    Java 14 之模式匹配,非常赞的一个新特性!
    poj 3661 Running(区间dp)
    LightOJ
    hdu 5540 Secrete Master Plan(水)
    hdu 5584 LCM Walk(数学推导公式,规律)
    hdu 5583 Kingdom of Black and White(模拟,技巧)
    hdu 5578 Friendship of Frog(multiset的应用)
    hdu 5586 Sum(dp+技巧)
    hdu 5585 Numbers
  • 原文地址:https://www.cnblogs.com/hustcser/p/4211119.html
Copyright © 2011-2022 走看看