[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++新型的转换,不用旧式转型

时间: 2024-10-13 22:29:46

[Effective C++ --027]尽量少做转型动作的相关文章

Effective C++ 阅读笔记_条款27 尽量少做转型动作

Effective C++ 阅读笔记_条款27 尽量少做转型动作 1.转型的三种形式,可以分为两大类. (1)旧式转型(old-style casts) (1.1) (T) expresstion (1.2) T (expression) (2) 新式转型(c++-style casts) (2.1)const_cast<T> (expression) (2.2)dynamic_cast<T> (expression) (2.3)reinterpret_cast<T>

Effective C++:条款27:尽量少做转型动作

(一)C风格旧式转型: (T)expression T(expression) (二)C++提供四种新式转型: (1)const_cast<T>(expression):去除表达式的常量性,是C++中唯一能做此操作的转型操作符. (2)dynamic_cast<T>(expression):主要用来执行"安全向下转型",即用来决定某对象是否归属继承体系中的某个类型.它是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作. (3)reinterp

条款27:尽量少做转型动作

条款27:尽量少做转型动作 C++的四种显示类型转换 ①reinterpret_cast(在编译期间实现转换) 将一个类型的指针转换成另一个类型的指针.这种转换不用于修改指针变量值数据存放的格式(不改变指针变量值),只需在编译期间重新解释指针的类型就可以做到,可以将指针值转换为一个整型数.但是不能用于非指针类型的转换,否则将不会通过编译. 意图执行低级转型,结果取决于编译器,故不可移植. ②const_cast(在编译期间实现转换) 用于去除指针变量的常量属性,将它转换为一个对应指针类型的普通变

条款27:尽量少做转型动作(Minimize casting)

NOTE : 1.如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts. 如果有个设计需要转型动作,试着发展无需转型的替代设计. 2.如果转型是必须要的,试着将它隐藏于某个函数背后.客户随后可以调用该函数,而不需要将转型放进他们自己的代码内. 3.宁可使用C++-style(新式)转型,不要使用旧式转型.前者很容易辨识出来,而且也比较有着分门别类的职撑.

Effective C++ Item 27 少做转型操作

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie todo Item34 旧式转型 (T) expression 或 T (expression) 新式转型 const_cast<T>(expression) 通常被用来将对象的常量性转除(cast away the constness) dynamic_cast<T>(expression) 执行"安全向下转型",也就是用来决定某对象是否归属继承体系中的

Effective C++ 条款27 尽量少做转型操作

1. 转型语法有三种, C风格转型:(T)expression 函数风格转型:T(expression) 两种方式除了小括号位置不同没有差别,可以称为"旧式转型". C++提供四种新式转型: const_cast<T>(expression): 将const变量引用或指针转为非const引用或指针,移除变量的常量特性.T必须是指针或引用. 注:虽然经const_cast转型后的变量可以被更改,但由于"常量折叠"(c++编译器在编译时将const 变量替换

Effective C++:规定27:尽量少做动作的过渡

(一个)C风格遗留转换: (T)expression T(expression) (二)C++提供四种新式转型: (1)const_cast<T>(expression):去除表达式的常量性.是C++中唯一能做此操作的转型操作符. (2)dynamic_cast<T>(expression):主要用来运行"安全向下转型",即用来决定某对象是否归属继承体系中的某个类型.它是唯一无法由旧式语法运行的动作,也是唯一可能耗费重大运行成本的转型动作. (3)reinter

C++ 转型动作 尽量避免 以及 那些意想不到的威胁

看完EffectiveC++的关于转型的章节,顿时认为周围的代码都处在悬崖边上~~ C的旧式转型:inta = 10; double b = (double)a; 对于C++的四种转型函数, const_cast去掉对象的常量性(仅仅此一个操作符有此功能!) dynamic_cast一般用于继承体系中某对象的归属,耗费较大 reinterpret_cast低级转型,差点儿不用. static_cast强迫隐式转换int->double, void * ->typed * 在类的expecili

Effective Item 9 - 尽量使可访问性最小化

模块设计是否良好,有个重要的因素在于,相对外部模块是否隐藏内部数据以及实现细节. 设计良好的模块会隐藏实现细节,并将API与其实现隔离开来. 模块之间通过API进行通信,对于内部工作情况互不可见. 即,封装(encapsulation)--软件设计的基本原则之一. 为什么要封装? 通过封装可以有效地接触各个模块之间的耦合关系,使这些模块可以独立地开发.测试.优化.使用.理解和修改. 即: ·可以增加开发效率,模块可以并行开发. ·封装可以减轻维护的负担,可以更有效的进行优化,且不会影响其他模块的