C++ 中的类型转换机制详解
Tips: This article based on Scott Meyers's <<Effective C++>> article 27: Minimize Casting
C++规则的设计目标之一,是保证"类型错误"绝对不可能发生。理论上你的程序可以很“干净”的通过编译,就表示它并不企图在任何对象身上执行任何不安全的,无意义的,愚蠢荒谬的操作。这是一个极具价值的保证,可别草率的放弃。
但是,转型(casting)却破坏了类型系统(type system)。
C++提供了三中不同类型的转化风格:
- C风格的转换: (T)expression
- 函数风格的转换: T(expression)
- 新式风格的转换(new-style or C++ style casts)
C++提供了4种形式的新式转换,每种形式的转换如下:
1)const_cast<T>(expression): const_cast 通常被用来将对象的常量性转除(cast away the constness)。它也是唯一具有此能力的的C++-style转型操作。
2)dynamic_cast<T>(expression): dynamic_cast 主要用来执行“安全向下转型”(Safe downcasting), 也就是用来决定某对象是否归属继承体系中的某个类型。
它是唯一一个无法用旧式语法执行的动作,也是唯一可能消耗重大运行成本的转型动作!(注:旧式风格的转换无法实现父类对象到子类对象的转换)
3) reinterpret_cast<T>(expression): 意图执行低级转型,实际动作(及结果)可能取决于编译器,这就表示它不可移植。这个转换多用在低级代码中。
4)static_cast<T>(expression):用来强迫隐式转换(implicit conversions), 例如将non-const对象转换为const对象,或将int转换位double等等。它也可以来
执行上述多种转换的反向转换。例如,其可以将void型的指针转换位typed型的指针,将pointer-to-base 转换为pointer-to-derived。但它无法将const转换成no-const,这
只有const_cast才能办得到!
许多程序员相信,转型其实什么都没有做,只是告诉编译器将一种类型视为另一种类型,这是错误的观念! 下面我们通过一个实例来验证转型期间编译器确实是做了什么!
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
/* 多重继承 */
class Base1
{
public:
Base1(const string& aName)
{
name = aName;
}
string getName()
{
return name;
}
private:
string name;
};
class Base2
{
public:
Base2(const string& aAddress)
{
address = aAddress;
}
string getAddress()
{
return address;
}
private:
string address;
};
class Drive : public Base1,public Base2
{
public:
Drive(const string& aName,const string& aAddress)
:Base1(aName),Base2(aAddress)
{
}
};
int main(void)
{
Drive drive_obj("jiang heng","fudan university");
Base1* base1_pt = &drive_obj;
Base2* base2_pt = &drive_obj;
Drive* drive_pt = &drive_obj;
cout<<"The Address of base1_pt: "<<base1_pt<<endl;
cout<<"The Address of base2_pt: "<<base2_pt<<endl;
cout<<"The Address of drive_pt: "<<drive_pt<<endl;
return ;
}
结果:
The Address of base1_pt: 0x7fffc9c64290
The Address of base2_pt: 0x7fffc9c64298
The Address of drive_pt: 0x7fffc9c64290
上述的实例表明C++中单一对象(例如上面的Drive对象)可以有一个以上的地址(比如上面Base2*类型的地址和Drive*类型的地址):
由此得到一个重要的结论对象的布局方式和它们的地址计算方式随着编译器的不同而不同,那意味着“由于知道对象如何布局”而设计的转型,
在某一平台上行得通,而在其他平台上不一定行得通。
关于转型的一个重要事实是你可能因此写出许多是是而非的代码,下面就是这样的一个实例:
1 #include <iostream>
2
3 using namespace std;
4
5 class Window
6 {
7 public:
8 Window(const int& wd,const int& hg)
9 :width(wd),height(hg)
{
}
int getWidth()
{
return width;
}
int getHeight()
{
return height;
}
virtual void onResize()
{
width += ;
height += ;
}
void printWindowMsg()
{
cout<<"The height of the window: "<<height<<endl;
cout<<"The width of the window: "<<width<<endl;
}
private:
int width;
int height;
};
class SpecialWindow : public Window
{
public:
SpecialWindow(const int& wd,const int& hg,const int& cor)
:Window(wd,hg)
{
color = cor;
}
virtual void onResize()
{
static_cast<Window>(*this).onResize();
color += ;
}
void printWindowMsg()
{
Window::printWindowMsg();
cout<<"The color of this window is: "<<color<<endl;
}
private:
int color;
};
int main(void)
{
SpecialWindow spwind(,,);
spwind.onResize();
spwind.printWindowMsg();
return ;
}
结果:
The height of the window: 30
The width of the window:
The color of this window is:
static_cast<Window>(*this).onResize();
上面这条语句将*this转型成Window,对函数onResize的调用因此调用了Window::onResize。但其调用的并不是当前对象上的函数,而是稍早转型
动作所创建的"*this对象之base class成分"的暂时副本上的OnResize!
将上面的语句改成:
Window::onResize();
结果:
The height of the window: 230
The width of the window:
The color of this window is:
显然达到了我们想要的效果!
上面这个例子说明了,如果你在程序中遇到了转型,那么这活脱脱就是一个警告信号!
tips: 出了要对一般的转型保持机敏和猜疑,更应该在注重效率的代码中对dynamic_cast保持机敏和猜疑!
只所以需要dynamic_cast,通常是因为你想在一个你认定为derived class对象身上执行derived class操作函数,但是你的手上只有一个"指向base"的pointer或reference,
你只能靠它们来处理对象!
下面是结局上述问题的一般的做法:
- 使用容器并在其中存储直接指向derived class对象的指针(通常是智能指针),这样就消除了"通过base class接口处理对象"的需要。
- 通过base class接口处理"所有可能之各种Window派生类",即在base class内提供virtual函数做你想对各个Window派生类想做的事。
优秀的C++代码很少使用转型,但要说完全摆脱它门又是不切实际的。
C++ 中的类型转换机制详解的更多相关文章
- JAVA中的GC机制详解
优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...
- Tomcat与Spring中的事件机制详解
最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认 ...
- C++ 中的RTTI机制详解
前言 RTTI是”Runtime Type Information”的缩写,意思是运行时类型信息,它提供了运行时确定对象类型的方法.RTTI并不是什么新的东西,很早就有了这个技术,但是,在实际应用中使 ...
- 关于MySQL中的锁机制详解
锁概述 MySQL的锁机制,就是数据库为了保证数据的一致性而设计的面对并发场景的一种规则. 最显著的特点是不同的存储引擎支持不同的锁机制,InnoDB支持行锁和表锁,MyISAM支持表锁. 表锁就是把 ...
- JAVA中的反射机制 详解
主要介绍以下几方面内容 理解 Class 类 理解 Java 的类加载机制 学会使用 ClassLoader 进行类加载 理解反射的机制 掌握 Constructor.Method.Field 类的用 ...
- react第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制)
第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制) 课程目标 深入理解和掌握事件的冒泡及捕获机制 理解react中的合成事件的本质 在react组件中合理的使用原生事件 ...
- 从mixin到new和prototype:Javascript原型机制详解
从mixin到new和prototype:Javascript原型机制详解 这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...
- 浏览器 HTTP 协议缓存机制详解
最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...
- JVM的垃圾回收机制详解和调优
JVM的垃圾回收机制详解和调优 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都 ...
随机推荐
- 多年的.NET开发,也只学会了这么几招
折腾了这么多年的.NET开发,也只学会了这么几招 软件开发不是生活的全部,但是好的生活全靠它了 随着工作年龄逐渐增加,身边的重担也越来越多.以前可以在公司加班到晚上10点,现在不行了.以前可以通宵 ...
- 9 个让 JavaScript 调试更简单的 Console 命令
一.显示信息的命令 <!DOCTYPE html> <html> <head> <title>常用console命令</title> < ...
- HP LoadRunner 11 破解及license
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 关于cocos2dx手游lua文件加密的解决方式
非常多使用cocos2dx+lua做游戏的同学.都会想到一个问题,我的游戏一旦公布,如何才干保证的我脚本代码不被破解.不泄露代码.尽管这和开源.共享的原则不合.可是代码也是coder的劳动成果,理应得 ...
- [MODx] 5. WayFinder
1. Install the wayFinder package 2. Select the resource which you want to show: The 'published' reso ...
- ios开发——实用技术OC-Swift篇&本地通知与远程通知详解
本地通知与远程通知详解 一:本地通知 Local Notification的作用 Local Notification(本地通知) :是根据本机状态做出的通知行为,因此,凡是仅需依赖本机状态即可判 ...
- Jordan Lecture Note-6: The Solutions of Nonlinear Equation.
The Solutions of Nonlinear Equation 本文主要介绍几种用于解非线性方程$f(x)=0$的一些方法. (1) Bisection Method. 算法: step 1: ...
- Android打包程序
右击项目->导出export next,完成相关信息填写将得到.apk文件,即可部署到手机上. 第一次: 然后打开目录就可以看到生成的apk,可以发布到各大市场上.
- Programme skills
1. Dynamic library 2. Template class. function template<typename T> classs Sample { ... templa ...
- 区块上的三角形状的css写法
.navbar .navline > .dropdown > .dropdown-menu:before { content: ''; display: inline-block; bor ...