C++中的显式类型转化
类型转化也许大家并不陌生,int i; float j; j = (float)i; i = (int)j; 像这样的显式转化其实很常见,强制类型转换可能会丢失部分数据,所以如果不加(int)做强制转换,严检查的编译会报错,宽检查的编译会报warning。在C语言中,指针是4字节或者8字节的,所以指针之间的强制转换在转换的时候就如同不同的整数类型之间的赋值,问题在于对该指针的使用上,必须确保该指针确实可以做出这样的强制转换。常见的情况是void*到不同的指针类型(比如内存分配,参数传递),char*和unsigned char*这样的转换。也有在读文件的时候,直接把某个结构映射为内存,写文件的时候,把某块内存直接映射成结构体。但其实在C++中,有用于专门用于显示类型转化的更合适更安全的语法。
主要包括四种:static_cast、const_cast、reinterpret_cast、dynamic_cast。四种转化的用途各不相同,下面一一介绍:
一、static_cast(静态转化)
语法:A = static_cast<typeA>(B)
把B显式转化为typeA类型,static_cast是最常用到的转化操作符,使用它可以消除因产生类型转化而可能产生的编译器warnings,static_cast全部用于明确定义的变换,包括编译器允许我们做的不用强制转换的“安全”变换和不太安全但清楚定义的变换。static_cast包含的转化类型包括典型的非强制类型转换、窄化变化(会有信息丢失)、使用void*的强制变换、隐式类型变换和类层次的静态定位(基类和派生类之间的转换)。
说明代码如下:
#include <iostream>
using namespace std; void func(int){} int main(){
int i = 0x7fff;
long l;
float f;
//情况1,向宽数据转化
l = i;
f = i;
//此时同样可以用static_cast
l = static_cast<long>(i);
f = static_cast<float>(i); cout << "l = " << l << endl;
cout << "f = " << f << endl; //情况2,向窄数据转化,可能发生精度丢失问题
i = l;
i = f;
cout << "i = " << i << endl;
//此时使用static_cast,类似于告诉编译器我清楚这种事情的发生,不用担心,也能消除警告
i = static_cast<int>(l);
i = static_cast<int>(f);
char c = static_cast<char>(i);
cout << "c = " << c << endl; //情况3,将void*类型强制转换为其他类型
void * vp = &i;
float* fp = (float*) vp;//这是一个危险的转换
fp = static_cast<float*>(vp);//这样同样危险 //情况4,隐式类型转换
double d = 0.0;
int x = d;//自动类型转化
x = static_cast<int>(d);//这样声明更加明显
func(d);//自动类型转化
func(static_cast<int>(d));//这样声明更加明显
}
更重要的应用是在于基类与派生类之间的转换
class Base{};
class derv:public Base{};
derv dd;
Base bb = static_cast(dd);//具有继承关系的类型之间转换
Base *pb = new Base;
derv *pd = static_cast(pb);//基类转继承类
derv* pd1 = new derv;
Base* pb1 = static_cast(pd1);//继承类指针转父类指针 二、const_cast(常量转换)
语法:A = const_cast<typeA>(B)
这个运算符可以用来去除一个对象的const或volatile属性。typeA必须是一个指针或者引用。
#include <iostream>
using namespace std;
int main(){
const int i = ;
int* j = (int*)&i;//不推荐使用的方法
j = const_cast<int*>(&i);
cout << *j << endl;
*j = ;
cout << *j << " " << i << endl;
}
三、reinterpret_cast(重解释转换)
语法:A = reinterpret_cast<typeA>(B)
这是一种最不安全的转换,最有可能出现问题,reinterpret_cast把对象假想为模式,仿佛它是一个完全不同类型的对象,这是低级的位操作,修改了操作数类型,但仅仅重新解释了对象的比特模型而没有进行二进制转换,在使用reinterpret_cast做任何事情之前,实际上总是需要它回到原来的类型。
从语法上看,这个操作符仅用于指针类型的转换(返回值是指针)。它用来将一个类型指针转换为另一个类型指针,它只需在编译时重新解释指针的类型。
这个操作符基本不考虑转换类型之间是否是相关的。
reinterpret_cast的本质(http://blog.csdn.net/coding_hello/archive/2008/03/24/2211466.aspx)一文做的试验很好的解释了reinterpret_cast不做二进制转换的特点。我喜欢从C语言的角度来理解这个操作符,就像C语言中的指针强制转换,其实只是把地址赋给了新的指针,其它的不做改变,只在新的指针使用的时候,进行不一样的解释。看如下的例子:
#include <iostream>
using namespace std;
const int sz = ; struct X {
int a[sz];
}; void print(X* x){
for(int i = ; i < sz; i++)
cout << x->a[i] << ' ';
cout << endl << "-------------------------" << endl;
} int main(){
X x;
print(&x);//输出尚未初始化的结构体内数组
int* xp = reinterpret_cast<int*>(&x);//重解释转换,取得x的地址并转换成一个整数指针
for(int* i = xp; i < xp + sz; i++)//然后用该指针遍历这个数组,置每个整数元素为0
*i = ;
print(reinterpret_cast<X*>(xp));
print(&x);
}
reinterpret_cast的思想就是当需要使用的时候,得到的东西已经转换成不同的类型了,以至于它不能用于类型原来的目的,除非再次把它转换回来。这里打印调用中转换回X*。xp只有作为int*才有用,这是对原来的X的重新解释。使用renterpret_cast通常不是一个明智的做法,但是当需要用到的时候,它是十分有用的。
reinterpret_cast常用的场景如下:
1)普通指针转换,T*—>U*—>T*,保证T*经过一些列转换值不变
比如将不同类型的指针存在一个容器里,vector可以存int*,char*,string*等各种指针,只要有别的方式确定某个void*当初的类型是T*,标准保证reinterpret_cast(v[i])可以得到当初的值。
2)自己做memory allocator,可以将T*转换为U*,这个时候可能要注意字节对其的问题。
四、dynamic_cast(动态转换)
语法:A=dynamic_cast<typeA>(B)
该运算符把B转换成typeA类型的对象。TypeA必须是类的指针、类的引用或者void *;
dynamic_cast的转换是在运行时进行的,它的一个好处是会在运行是做类型检查,如果对象的类型不是期望的类型,它会在指针转换的时候返回NULL,并在引用转换的时候抛出一个std::bad_cast异常。
dynamic_cast一般只在继承类对象的指针之间或引用之间进行类型转换。如果没有继承关系,则被转化的类具有虚函数对象的指针进行转换。
struct A {
virtual void f() { }
};
struct B : public A { };
struct C { }; void f () {
A a;
B b; A* ap = &b;
B* b1 = dynamic_cast (&a); // NULL, because 'a' is not a 'B'
B* b2 = dynamic_cast (ap); // 'b'
C* c = dynamic_cast (ap); // NULL. A& ar = dynamic_cast (*ap); // Ok.
B& br = dynamic_cast (*ap); // Ok.
C& cr = dynamic_cast (*ap); // std::bad_cast
}
C++中的显式类型转化的更多相关文章
- javascript中的隐式类型转化
javascript中的隐式类型转化 #隐式转换 ## "+" 字符串和数字 如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作. 如果其中一个操作数是对 ...
- item 6: 当auto推导出一个不想要的类型时,使用显式类型初始化的语法
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 Item 5解释了比起显式指定类型,使用auto来 ...
- [Effective Modern C++] Item 5. Prefer auto to explicit type declarations - 相对显式类型声明,更倾向使用auto
条款5 相对显式类型声明,更倾向使用auto 基础知识 auto能大大方便变量的定义,可以表示仅由编译器知道的类型. template<typename It> void dwim(It ...
- Spring装配bean(在java中进行显式配置)
1.简单介绍 Spring提供了三种装配机制: 1.在XML中进行显式配置: 2.在java中进行显式配置: 3.隐式的bean发现机制和自动装配. 其中,1和3项在项目中经常使用,而在java中进行 ...
- 008.在C#中,显式接口VS隐式接口
原文http://www.codeproject.com/Articles/1000374/Explicit-Interface-VS-Implicit-Interface-in-Csharp (At ...
- selenium-webdriver中的显式等待与隐式等待
在selenium-webdriver中等待的方式简单可以概括为三种: 1 导入time包,调用time.sleep()的方法传入时间,这种方式也叫强制等待,固定死等一个时间 2 隐式等待,直接调用i ...
- C#中的隐式类型var——详细示例解析
从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,它的具体类型由编译器根据上下文推断而出. 下面就让我来总结下隐式类型的一些特点: 1.va ...
- javascript显式类型的转换
显式类型转换目的:为了使代码变得清晰易读,而做显示类型的转换常使用的函数:Boolean(),String(),Number()或Object()如:Nunber(5) //5String(true) ...
- Java :构造器中的显式参数和this隐式参数
1.构造器 写一个Java类,首先要先从构造器开始,构造器与类同名,在构造类的对象时会先从构造器开始. 构造器总是伴随着new操作符的执行而被调用. 构造器主要是用来初始化类的实例域. 构造器的特点: ...
随机推荐
- windows下nginx安装、配置与使用(转载)
目前国内各大门户网站已经部署了Nginx,如新浪.网易.腾讯等:国内几个重要的视频分享网站也部署了Nginx,如六房间.酷6等.新近发现Nginx 技术在国内日趋火热,越来越多的网站开始部署Nginx ...
- Linux 昨天时间
今天date +%F昨天date -d yesterday +%F明天date -d tomorrow +%F七天前date -d "7 days ago" +%F
- Java职业生涯规划
java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈 ...
- SqlServer 2008登录时报错
登录SQLServer2008R2时提示如下错误: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法访问服务器.请验证实例名称是否正确并且 SQL Server ...
- Java 中使用javah编译头文件出现找不到类的情况
在工程的bin目录下,输入命令: javah -classpath . -jni 类路径.JNI类
- 关于 Java(TM) Platform SE binary 已停止工作 的解决方法
一.问题描述 昨天晚上Myeclipse还用着好好的,今天早上打开工程,只要运行就卡住,大半天弹出个消息窗口:Java(TM) Platform SE binary 已停止工作. 如图 关闭Myecl ...
- leetcode 137[转]
没思路.网上找到的. 1. 将每一个int看成32位数,统计每一位出现的次数对3取余,所以需要开辟一个32大小的数组来统计每一位出现的次数 2. 对第一种思路进行简化,模拟3进制: three two ...
- 禁止换行“white-space:nowrap;”!
"white-space:nowrap;" <html> <div class="box">精彩的生活,精彩的世界</div> ...
- display用法:
用法: 1.display:fixed: 存在于position定位top,left,right,bottom,fixed:脱离文档流的针对于浏览器窗口大小定位,可以更好的解决"缩小浏览器窗 ...
- 3.4.4 数据预留和对齐(skb_reserve, skb_push, skb_put, skb_pull)
转自:http://book.51cto.com/art/201206/345043.htm <Linux内核源码剖析:TCP/IP实现>本书详细论述了Linux内核2.6.20版本中TC ...