C的转型方式存在以下两个缺点:

1)几乎允许你将任何类型转化为任何类型,不能精确的指明转型意图,这样很不安全

如将一个pointer-to-base-class-object转型为一个pointer-to-derived-class-object(改变一个对象的类型)和将一个pointer-to-const-object转型为一个pointer-to-non-const-object(改变对象的常量性),在旧式C语法中并不区分。

2)其语法结构难以辨识,容易被混淆

旧式C转型方式的语法为(type)expression,由一对小括号加上一个对象名称组成,而这种语法结构在C++的任何地方都有可能使用,这就无法很直观地判断出是否是转型操作。

为了解决C旧式转型的缺点,C++引用了4个新的转型操作符

1)static_cast

static_cast基本上拥有和C旧式转型相同的威力与意义

#include<bits/stdc++.h>
using namespace std;
int main()
{
//计算两个int型数相除,结果为double型
int first_num=1;
int second_num=2;
double ans1 = (double)first_num/second_num;//旧式C语法
double ans2 = static_cast<double>(first_num)/second_num;//新式C++转型符
cout<<ans1<<endl;//0.5
cout<<ans2<<endl;//0.5
}

但是static_cast不能移除表达式的常量性,因为有一个专门的转型操作符const_cast来处理这种情况

2)const_cast

const_cast用来移除表达式中的常量性或者变易性,也仅仅只有这个功能

只能是const_cast<对象的引用或对象的指针>的形式,不能是const_cast<对象>的形式

#include<bits/stdc++.h>
using namespace std;
int main()
{
int num=10;
const int *cpNum=&num;
//int *p1=cpNum; //error:cannot convert from 'const int *' to 'int *'
int *p2=(int*)cpNum; //旧式C
int *p3=const_cast<int*>(cpNum); //新式C++const_cast移除常量性 cout<<*p2<<endl;//10
cout<<*p3<<endl;//10
}

const_cast最常见的用途就是将某个对象的常量性去除掉

3)dynamic_cast

用来执行继承体系中安全的向下转型或跨系转型动作,dynamic_cast支持RTTI运行时类型检查

比如将指向基类对象的指针或引用转型为子类对象的指针或引用,并且可以得知转型是否成功,如果转型失败会以一个空指针(转型对象为指针)或异常(转型对象为引用)

需要注意的是,dynamic_cast无法应用在缺乏虚函数的类上,理由如下:

dynamic_cast的转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等),而要获得这些信息,就需要通过虚函数表,在C++对象模型中对象实例最前面的就是虚函数指针,通过虚函数表指针可以获取到该类对象的所有虚函数,包括父类的,因为派生类会继承基类的虚函数表,所以通过这个虚函数表,我们就可以知道该类对象的父类,在转换的时候就可以判断对象有无继承关系

另外,dynamic_cast支持交叉转换,基类A有两个直接派生类B和C,那么将B类对象指针/引用转换为C类对象指针/引用的转换称之为交叉转换

class Base
{
virtual void fun()
{
cout << "Base" << endl;
}
}; class Derived :Base
{
virtual void fun()
{
cout << "Derived" << endl;
}
}; Base* bbb = new Base();
Derived* aaa = dynamic_cast<Derived*> (bbb);
Derived& ccc = dynamic_cast<Derived&> (*bbb);

如果你需要转换一个不涉及继承体制的请使用:static_cast,dynamic_cast仅仅适用于那种”所指对象至少有一个虚函数“的指针身上。

4)reinterpret_cast

最常用的用途是转换“函数指针”,但是函数指针的转型动作,并不具备移植性,某些情况下函数指针转型会导致不正确的结果,所以我们应该尽量避免将函数指针转型

typedef void (*FuncPtr)()  //FuncPtr是个指针,指向某个函数,后者无需任何自变量,返回值为void

FuncPtr funcPtrArray[10]   //funcPtrArray是个数组,内含10个FuncPtr

假设现在有某种原有,需要将一个返回值为int类型的函数放入funcPtrArray

int dosomething()

将int类型函数指针放入int类型函数指针数组,如果没有转型的话,是不可能做到这一点的

funcPtrArray[0]=&dosomething  //错误,类型不符合

使用reinterpret_cast,可以强迫编译器了解你的意图

funcPtrArray[0]=reinterpret_cast<FuncPtr>(&dosomething)  //正确,将int类型函数指针转换为void类型

最新文章

  1. [LeetCode] Wildcard Matching 外卡匹配
  2. mybatis入门基础(六)----高级映射(一对一,一对多,多对多)
  3. Swift与OC混编
  4. js选项卡
  5. 赞!带进度条的 jQuery 文件拖放上传插件
  6. Unity3d 制作物品平滑运动
  7. [原创]java WEB学习笔记100:Spring学习---Spring Bean配置:SpEL详细介绍及代码演示
  8. 安卓开发--android library projects cannot be launched错误
  9. ListView缓存机制踩过的坑
  10. 认识C和内存管理
  11. SQLITE LIMIT
  12. php 文件上传 以及保存在本地的乱码问题处理
  13. 开源cms
  14. 系统内存和CPU管理、监控
  15. SQL 结构化查询语言
  16. asp.net 中的错误跳转 customerrors 对html文件不起作用
  17. 关于多线程中GCD的使用
  18. gradle 排除jar包依赖
  19. SpirngBoot之整合Swagger2
  20. 微擎查询SQL语句常用

热门文章

  1. ASP.NET 中关GridView里加入CheckBox 在后台获取不到选中状态的问题
  2. python numba讲解
  3. golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的
  4. 简单记录(css换行带点与不带点)
  5. 【推荐】全球最全面的Telegram组群频道的集合网站 持续收集中
  6. mssql 收缩日志
  7. DjangoForm 提交验证
  8. python使用ftplib模块实现FTP文件的上传下载
  9. linux下c语言实现多线程文件复制【转】
  10. vm|vmware workstation 15|14 pro 激活|密钥|序列号|许可证