快速理解关于括号运算符、static_cast、dynamic_cast和reinterpret_cast
来源:互联网 发布:淘宝网店怎么修改电话 编辑:程序博客网 时间:2024/06/01 11:13
http://blog.csdn.net/superarhow/article/details/1007875
不知道有没有误导读者。好在从阅读数量来看应该不会误导很多人吧。。。
关于这几个运算符的区别,各个地方的资料已经很多了。这篇文章是希望用比较浅显易懂的表达方式,写给希望快速理解它们,以及了解不正确使用它们会带来什么后果的读者们看的。笔者水平有限,如有疏漏之处,还请不吝指正。
首先指出,括号运算符是可以完成所有的转换的。那么第一个问题就是:为什么C++要引入这么几个cast?既然括号就已经足够了?
来看下面这一个例子:
class CItem{public: void SetOwner(void* o) { _owner = o; }public: void* _owner;};
class CBanana{};
template<typename ItemClass_>class CContainer{public: void AddItem(int index, ItemClass_* i) { _items[index] = (CItem*)i; ((CItem*)i)->SetOwner(this); }public: CItem* _items[10];};
int main(int argc, char** argv){ CItem* item = new CItem; CContainer<CItem> c; c.AddItem(0, item); CContainer<CBanana> basket; CBanana b; basket.AddItem(0, &b); // <---- Here return 0;}
CContainer希望它的子类继承自CItem,以调用它的SetOwner方法。因此在AddItem而是在中间用了(CItem*)这样的cast。
第一个对AddItem的调用是没有问题的。第二个调用,可以看到,CBanana类既不是CItem类的子类,而且也没有实现SetOwner方法,但是编译器没有给出任何警告!运行这段程序将毫无疑问的引起程序crash。
所有的cast运算符,都是为了实现“将X当作Y"的功能。那么就会有下面两个问题:
1. 如何将X当作Y?
2. X能不能被当作Y?如果不能,怎么办?
例如:如何把一个整数当作一个指针?它们本是无关的东西。隐含的操作是这个整数是指针的地址。这种转换是reinterpret_cast。即不管原来类型如何,都以它们各自自己的意义解释,进行转化。在我们上面这个例子中,括号就相当于完成了一次reinterpret_cast。
关于问题2,我们将上面的例子改为用static_cast,那么在编译时,编译器将会出错:
error: invalid static_cast from type 'CBanana*' to type 'CItem*'
这就达到了我们的要求。
dynamic_cast和static_cast类似,更为强大的是,它会在运行时检查指针的类型,如果类型不一致,则会返回NULL。当然它需要程序编译时有RTTI信息。
所以简而言之,static_cast和dynamic_cast都是用于对象类型的转换。
reinterpret_cast还有什么危险性呢?再看一个例子:
class CFruit{public: virtual void drink() { printf("%s\n", _juice); } CFruit() : _juice("tomato ice") {}private: char* _juice;};class CVegetable{public: virtual void cook() { printf("%s\n", _dish); } CVegetable() : _dish("tomato egg") {}private: char* _dish;};class CTomato : public CFruit, public CVegetable{public: virtual void eat() { drink(); cook(); }};
int main(int argc, char** argv){ CTomato* tomato = new CTomato; /// 1 ((CVegetable*)tomato)->cook(); ((CFruit*)tomato)->drink();
/// 2 void* p = tomato; ((CVegetable*)p)->cook(); ((CFruit*)p)->drink();
/// 3 p = (CVegetable*)tomato; ((CVegetable*)p)->cook(); ((CFruit*)p)->drink();
printf("(CTomato*)tomato=%p (CFruit*)tomato=%p (CVegetable*)tomato=%p\n", (CTomato*)tomato, (CFruit*)tomato, (CVegetable*)tomato); return 0;}
猜猜看第1,2,3段都会打印出什么?然后再让最后一句printf来告诉你答案。
第1段会打印出正确结果,而2则两个都是tomato ice;3则两个都是tomato egg。
我们这里的括号也是reinterpret_cast,因为void*不含任何类型信息。而在一个多重继承的对象中,CTomato的内存组织如下:
+0 [CTomato/CFruit] +N [CVegetable]
CTomato和CFruit的部份是指向同一个地址,而CVegetable则需要一个偏移。因此,在使用reinterpret_cast时,CTomato和CFruit不会有任何问题,但CVegetable的部份就会出错了。以上例子只是出错,而实际使用中,因为对象布局的不同,通常都是以crash告终。
那么为什么1的部份正确呢?因为它是对象间的转换,有对象信息,因此编译器实际上是使用了static_cast来进行的转换。这个转换翻译成汇编语言,也就是加或减去CVegetable和CTomato之间的对象偏移值。
- 快速理解关于括号运算符、static_cast、dynamic_cast和reinterpret_cast
- static_cast, const_cast, dynamic_cast, 和 reinterpret_cast理解
- C++ const_cast static_cast dynamic_cast reinterpret_cast运算符
- C++ const_cast static_cast dynamic_cast reinterpret_cast运算符
- 关于const_cast, static_cast, dynamic_cast和reinterpret_cast
- static_cast,dynamic_cast和reinterpret_cast
- static_cast, dynamic_cast和reinterpret_cast
- static_cast, dynamic_cast和reinterpret_cast
- 关于static_cast、dynamic_cast、const_cast、reinterpret_cast
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- static_cast、dynamic_cast、reinterpret_cast和const_c
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- dynamic_cast、static_cast、const_cast 和 reinterpret_cast
- static_cast、dynamic_cast、reinterpret_cast、和const_cast
- linux 2.6.28.7 各驱动代码位置(待验证,已验证为蓝色标识)
- Response.Redirect传递参数
- 烘干设备技术的开发及应用需要具备哪些条件
- 跟我一起学Python之五:序列
- 奇怪的现象
- 快速理解关于括号运算符、static_cast、dynamic_cast和reinterpret_cast
- Flash图表FusionCharts如何自定义图表导出菜单或界面
- aaaaaaa
- Unit test enables develop in baby steps thus improve the efficiency
- eclipse maven plugin 插件 安装 和 配置
- Subversion服务器程序版本说明
- css中设置前景色的透明度
- LXC 简单实用说明
- 字符串汉字英文数字判断