温故而知新 C++ 类型转换
C语言类型转换
在C语言里用到的类型转换方式,一般都是用强制类型转换,语法:(类型说明符)(表达式),例如: (float)a 把a转换为实型,(int)(x+y) 把x+y的结果转换为整型。
C语言这种赋值时的类型转换形式可能会使人感到不精密和不严格,因为不管表达式的值怎样,系统都自动将其转为赋值运算符左部变量的类型。
C++类型转换
const_cast,字面上理解就是去const属性。
static_cast,命名上理解是静态类型转换。如int转换成char。
dynamic_cast,命名上理解是动态类型转换。如子类和父类之间的多态类型转换。
reinterpret_cast,仅仅重新解释类型,但没有进行二进制的转换。
const_cast:
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
#include <stdio.h>
using namespace std;
struct Data{
int value;
};
int main(int argc, _TCHAR* argv[])
{
const Data data1 = {};
//data1.value = 15; //error C3892: “data1”: 不能给常量赋值
Data &data2 = const_cast<Data &>(data1);
data2.value = ;
printf("data1.value = %d data2.value = %d\n",data1.value,data2.value);
const int a = ;
int *b = const_cast<int*>(&a);
*b = ;
printf("a = %d b == &a is %d\n",a,b == &a);
system("pause");
return ;
}
dynamic_cast
有条件转换,动态类型转换,运行时类型安全检查(转换失败返回NULL):
1. 安全的基类和子类之间转换。
2. 必须要有虚函数。
3. 相同基类不同子类之间的交叉转换。但结果是NULL。
class BaseClass {
public:
int m_iNum;
virtualvoid foo(){}; //基类必须有虚函数。保持多台特性才能使用dynamic_cast
};
class DerivedClass: public BaseClass {
public:
char*m_szName[];
void bar(){};
};
BaseClass* pb =new DerivedClass();
DerivedClass *pd1 = static_cast<DerivedClass *>(pb); //子类->父类,静态类型转换,正确但不推荐
DerivedClass *pd2 = dynamic_cast<DerivedClass *>(pb); //子类->父类,动态类型转换,正确
BaseClass* pb2 =new BaseClass();
DerivedClass *pd21 = static_cast<DerivedClass *>(pb2); //父类->子类,静态类型转换,危险!访问子类m_szName成员越界
DerivedClass *pd22 = dynamic_cast<DerivedClass *>(pb2); //父类->子类,动态类型转换,安全的。结果是NULL
static_cast:
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。(int* 转 long* error C2440: “static_cast”: 无法从“int *”转换为“long *”)
④把任何类型的表达式转换成void类型。
reinterpret_cast:
reinterpret_cast<type-id> (expression)
type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)
主要是将原地址的值重新强制定义为新类型。
reinterpret_cast与static_cast的类型转换比较:
#include <stdio.h> using namespace std; class A
{
public:
int m_a;
}; class B
{
public:
int m_b;
}; class C:public A,public B
{ }; int main(int argc, _TCHAR* argv[])
{ C* c = new C();
c->m_a = ;
c->m_b = ; A* a1 = static_cast<A*>(c);
A* a2 = reinterpret_cast<A*>(c); B* b1 = static_cast<B*>(c);
B* b2 = reinterpret_cast<B*>(c); printf("c = %p,a1 = %p,b1 = %p\n",c,a1,b1);
printf("c = %p,a2 = %p,b2 = %p\n",c,a2,b2); printf("a1.m_a = %d, b1.m_b = %d\n",a1->m_a,b1->m_b);
printf("a2.m_a = %d, b2.m_b = %d\n",a2->m_a,b2->m_b); system("pause");
return ;
}
运行结果:
c = ,a1 = ,b1 =
c = ,a2 = ,b2 = 00392950
a1.m_a = , b1.m_b =
a2.m_a = , b2.m_b = 1
由运行结果可以很明显地看到,使用reinterpret_cast进行强制转换的时候b2直接是从c的地址开始,将c转换成了b2,而使用static_cast的时候,b1是进行了一个sizeof(A)的一个偏移量的位移,也就是说在多重继承的情况下,将子类的对象指针转换成基类对象指针,使用static_cast才是安全的。reinterpret_cast的目的是将类型重定义,除非你非常明确地希望指向的那一块内存是希望定义到你要转换的目标,否则慎用。
reinterpret_cast的一个使用例子:
#include <stdio.h> using namespace std; typedef void(*FuncPtr)();
typedef int(*FuncPtr2)(); void fun1()
{
} int fun2()
{
return ;
} int main(int argc, _TCHAR* argv[])
{
FuncPtr fun[];
fun[] = &fun1; //fun[1] = &fun2; //error C2440: “=”: 无法从“int (__cdecl *)(void)”转换为“FuncPtr”
//fun[1] = static_cast<FuncPtr>(&fun2); //error C2440: “static_cast”: 无法从“int (__cdecl *)(int)”转换为“FuncPtr” fun[] = reinterpret_cast<FuncPtr>(&fun2); //用强制转换将int fun 转为 void fun 保存起来 FuncPtr2* pfun = reinterpret_cast<FuncPtr2*>(&fun[]); //在需要使用的时候,再转换回来 printf("run pfun = %d\n",(*pfun)()); //打印得到 "run pfun =10" system("pause");
return ;
}
温故而知新 C++ 类型转换的更多相关文章
- javascript 基础教程[温故而知新一]
子曰:“温故而知新,可以为师矣.”孔子说:“温习旧知识从而得知新的理解与体会,凭借这一点就可以成为老师了.“ 尤其是咱们搞程序的人,不管是不是全栈工程师,都是集十八般武艺于一身.不过有时候有些知识如果 ...
- 为C# as 类型转换及Assembly.LoadFrom埋坑!
背景: 不久前,我发布了一个调试工具:发布:.NET开发人员必备的可视化调试工具(你值的拥有) 效果是这样的: 之后,有小部分用户反映,工具用不了(没反应或有异常)~~~ 然后,建议小部分用户换个电脑 ...
- c# 基础 object ,new操作符,类型转换
参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...
- Struts2日期类型转换
针对日期类java.util.Date进行类型转换,要求客户端使用"yyyy-MM-dd","yyyy/MM/dd"中的任意一种输入,并以"yyyy- ...
- 【.NET深呼吸】基础:自定义类型转换
照例,老周在开始吹牛之前,先讲讲小故事,这是朋友提出的建议,老TMD写技术有什么了不起的,人人都会写.后来老周想想,也确实,代码谁不会写,能写到有品位有感悟,就不容易做到.于是,老周接受了该朋友的建议 ...
- C++四种类型转换方式。
类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比 ...
- struts2类型转换
1. Struts2中的类型转换 我们知道通过HTTP提交到后台的数据,都是字符串的形式,而我们需要的数据类型当然不只字符串类型一种.所以,我们需要类型转换! 在Struts2中,类型转换的概念除了用 ...
- C++_系列自学课程_第_11_课_类型转换_《C++ Primer 第四版》
上次说了关于表达式的一些内容,说到还有一些关于数据类型转换的内容,今天我们接着八一八C++中的数据类型转换. 一.隐式类型转换 在表达式中,有些操作符可以对多种类型的操作数进行操作, 例如 + 操作符 ...
- Struts2入门(三)——数据类型转换
一.前言 笔者一直觉得,学习一个知识点,你首先要明白,这东西是什么?有什么用?这样你才能了解.好了,不说废话. 1.1.类型转换为何存在?什么是类型转换? 在MVC框架中,都是属于表示层解决方案,都需 ...
随机推荐
- 读《细说php》,php要点随记
近期读<细说php>,其实知识要点都接触过,体会下不同书籍对相同知识的描述差异,达到温故知心的目的. 未按章节顺序读,所谓要点并不是提纲式的所有要点,只是自己觉得工作中很重要(但是掌握的不 ...
- lyGrid表格插件
表格基础参数: grid = lyGrid({ l_column : [{//表格列表数据 colkey : null, ...
- git上解决代码冲突
1.切换到master: git co master 2.拉最新代码:git pull origin master 3.删掉多余符号 4.切换到提交的分支:git br Txxxx 5.合并:git ...
- storyBoard方式ScrollView的AutoLayout
在使用storyboard和xib时,我们经常要用到ScrollView,还有自动 布局AutoLayout,但是ScrollView和AutoLayout 结合使用,相对来说有点复杂.根据实践,我说 ...
- 狗血phonegap备忘录[3.3]
phonegap平台就是个狗血的坑,最近的一个项目技术因为上面选型失败,使用了phonegap,加上客户的要求是"像微信一样",真可谓历经坎坷. 基本上评估一个项目是否应该或者可以 ...
- 给想上MIT的牛学生说几句
[来信] 老师您好! 非常冒昧的来打搅您,仅仅是在学习上实在有些困惑才来向您求教一番. 我是计算机科学与技术的大一学生,我非常喜欢我自己的专业,可是学校里讲的东西太慢,太浅,所以我一般都是自学,我在自 ...
- 在安装twincat plc时,出现 there are some files marked for deletion on next reboot.please reboot first then
在注冊表内"HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\ "中删除注冊表值 " ...
- noip 2012 疫情控制
/* 考试的时候没想出正解 也没打暴力 时间不够了 随便yy了几种情况按出现的先后顺序处理而没有贪心 的了20分 不粘了 正解是围绕首都的儿子来搞的 显然先二分答案 对于每个限定的最大时间 我们尝试着 ...
- DEDECMS织梦列表页每隔N行文章添加一条分隔线
这是给一个朋友做模板的时候,用到的一个小小的技巧,今天正好用上了,以前看到有人问过不知道解决没有,今天整理了一下,本想保存在自己的电脑里,后来一想,不如咱们一起共享一下,也是对织梦的感恩,有好东西就来 ...
- java常见错误的列表
ava常见错误列表: 找不到符号(symbol) 类X是public的,应该被声明在名为X.java的文件中 缺失类.接口或枚举类型 缺失X 缺失标识符 非法的表达式开头 类型不兼容 非法的方法声明; ...