[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属性,也就是说允许你对常量进行修改。
第二节 转型的使用
假设我们有以下的代码
class Base {...};
class Derived: public Base {...};
Derived d;
Base* pb = &d; // 隐喻的将Derived*转换为Base*
在上述代码中,我们建立了一个base class指针指向派生类对象,但有时候上述的两个指针的值并不相同。这种情况下会有偏移量在运行期间被施与Derived指针上,用以取得正确的Base*指针值。
这就表明,单一对象(比如派生类对象)可能拥有一个以上的地址(比如以Base*指向它时的地址和以Derived*指向它时的地址)。事实上,一旦发生多重继承,这事一直都在发生。
需要注意的是:上面的偏移量是随着编译器不同而不同的。
在调用基类的虚函数的时候,也很容易出现以下的问题:
需求:在基类和派生类都定义了虚函数的时候,如果我们想要在派生类中调用父类的函数。
class Base {
public:
virtual void onResize() {...};
};
class Device: public Base {
public:
virtual void onResize() {
static_cast<Base>(*this).onResize(); // 调用基类的onResize函数,实际是不可行的
...
}
};
在红色的代码中,*this转型为Base,调用Base::onResize。但是,它调用的并不是当前对象上的函数,而是稍早转型动作所建立的一个“*this对象的Base Class”的副本。
改法很简单,拿掉转型,直接调用即可:
class Base {
public:
virtual void onResize() {...};
};
class Device: public Base {
public:
virtual void onResize() {
Base::onResize(); // 调用基类的onResize函数
...
}
};
在这一节中,作者还讲述了两种避免转型的方法,其实原理都是一样的:直接调用,避免过多的转型!
◆总结
1.如果可以,尽量避免转型,特别是在注重效率的代码中避免使用dynamic_cast
2.如果必须要转型,请试着将其隐藏在某个函数背后
3.宁可使用C++新型的转换,不用旧式转型
[Effective C++ --027]尽量少做转型动作的更多相关文章
- 读书笔记_Effective_C++_条款二十七:尽量少做转型动作
有关转型的几种做法,已经在早些的博客中写过了.这里先简单回顾一下,再讲一讲effective中对之更深入的阐述. 转型可以按风格可以分成C风格转型和C++风格转型两大类,C风格转型很容易看到,因为我们 ...
- Effective C++ -----条款27:尽量少做转型动作
如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts.如果有个设计需要转型动作,试着发展无需转型的替代设计. 如果转型是必要的,试着将它隐藏于某个函数背后.客户随后可以调用该 ...
- 条款27:尽量少做转型动作(Minimize casting)
NOTE : 1.如果可以,尽量避免转型,特别是在注重效率的代码中避免dynamic_casts. 如果有个设计需要转型动作,试着发展无需转型的替代设计. 2.如果转型是必须要的,试着将它隐藏于某个函 ...
- [EffectiveC++]item27:尽量少做转型动作
- Effective C++ Item 27 少做转型操作
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie todo Item34 旧式转型 (T) expression 或 T (expressio ...
- Effective C++:规定27:尽量少做动作的过渡
(一个)C风格遗留转换: (T)expression T(expression) (二)C++提供四种新式转型: (1)const_cast<T>(expression):去除表达式的常量 ...
- 读书笔记 effective c++ Item 27 尽量少使用转型(casting)
C++设计的规则是用来保证使类型相关的错误不再可能出现.理论上来说,如果你的程序能够很干净的通过编译,它就不会尝试在任何对象上执行任何不安全或无意义的操作.这个保证很有价值,不要轻易放弃它. 不幸的是 ...
- C++ 转型动作 尽量避免 以及 那些意想不到的威胁
看完EffectiveC++的关于转型的章节,顿时认为周围的代码都处在悬崖边上~~ C的旧式转型:inta = 10; double b = (double)a; 对于C++的四种转型函数, cons ...
- Effective Objective-C 2.0 — 第二条:类的头文件中尽量少引入其他头文件
第二条:类的头文件中尽量少引入其他头文件 使用向前声明(forward declaring) @class EOCEmployer 1, 将引入头文件的实际尽量延后,只在确有需要时才引入,这样就可以减 ...
随机推荐
- Fiddler的基本介绍
fiddler 简介: 一款免费且功能强大的数据包抓取软件.它通过代理的方式获取程序http通讯的数据,可以用其检测网页和服务器的交互情况,能够记录所有客户端和服务器间的http请求,支持监视.设置断 ...
- Java [leetcode 12] Integer to Roman
题目描述: Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range fr ...
- [html5] (Notification) 桌面通知
前几天要做一个桌面通知的功能,翻查以前做的笔记,发现webkitNotifications这个已经不能用了,baidu了下,基本都是介绍webkitNotifications的,后来在SOF上找到答案 ...
- NopCommerce源码架构详解--初识高性能的开源商城系统cms
很多人都说通过阅读.学习大神们高质量的代码是提高自己技术能力最快的方式之一.我觉得通过阅读NopCommerce的源码,可以从中学习很多企业系统.软件开发的规范和一些新的技术.技巧,可以快速地提高我们 ...
- 【JS】Advanced1:Object-Oriented Code
Object-Oriented Code 1. var Person = function (name) { this.name = name; }; Person.prototype.say = f ...
- openCV 直方图统计
直方图显示 #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main(int argc ...
- 分享两个模拟get和post方法的工具类,让应用能够与服务器进行数据交互
很久没有码字了,今天跟大家分享一个模拟get和post方法的工具类,在安卓应用中很多都需要跟服务器进行数据交互,这需要两方面的配合,首先服务器端会给应用提供一些数据交互的接口,可是怎样在应用中去调用呢 ...
- 在C中定义一个动态的二维数组
一般来讲两种办法: 第一种:连续内存分配 #include "stdio.h" #include "stdlib.h" int main() { int x,y ...
- CF390-E. Inna and Large Sweet Matrix(区间更新+区间查询)
题意很好理解,不说了 题解就是每次把值压缩成一维,比如x上,这样就可以求出任意宽度的整个竖条的和. 如这张图,求的是s5-(s1+s3+s7+s9) 因为可以求出一整竖条和一整横条,我们可以求出是s2 ...
- dynamic调用时报RuntimeBinderException:“object”未包含“xxx”的定义 错误
情况如下:两个项目项目A命名空间 Test.PA 匿名类型所在 项目B命名空间 Test.PB 在Test.PB 中通过dynamic关键字调用Test.PA中匿名类型时报上述错误 解决办法 在项 ...