在c++中进行类型转换只需要在变量前加上变量类型,并且转换是双向的。

例如:

int i = 0;
double d = 1.9;int i1 = (int) d;
double d1 = (double) i;

这种类型转换方式只适用于基本数据类型,对复杂的自定义类型不适用。

因此,C++中提供了四种类型转换符:static_cast、dynamic_cast、const_cast、reinterpret_cast。


1、dynamic_cast

dynamic_cast用于类继承层次间的指针或引用转换。主要还是用于执行“安全的向下转型(safe downcasting)”,也即是基类对象的指针或引用转换为同一继承层次的其他指针或引用。至于“向上转型”(即派生类指针或引用类型转换为其基类类型),本身就是安全的,尽管可以使用dynamic_cast进行转换,但这是没必要的, 普通的转换已经可以达到目的,毕竟使用dynamic_cast是需要开销的。

不同于其它的强制类型转换,dynamic_cast在运行时会进行类型检查,如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失败:

class Base(){virtual void dummy(){} };
class Derived:public Base{};Base *b1 = new Base;
Base *b2 = new Derived;Derived *b2d1 = dynamic_cast<Derived*>(b1);   //转换失败,返回NULL
Derived *b2d2 = dynamic_cast<Derived*>(b2);    //转换成功Derived &b2d3 = dynamic_cast<Derived&>(*b1);   //转换失败,抛出异常
Derived &b2d4 = dynamic_cast<Derived&>(*b2);    //转换成功

对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;

对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。

dynamic_cast是四个强制类型转换操作符中最特殊的一个,它支持运行时识别指针或引用

首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,

这种检查不是语法上的,而是真实情况的检查。

dynamic_cast与继承层次的指针

对于“向下转型”有两种情况。

一种是基类指针所指对象是派生类类型的,这种转换是安全的;

另一种是基类指针所指对象为基类类型,在这种情况下dynamic_cast在运行时做检查;

#include "stdafx.h"
#include<iostream>
using namespace std;class Base
{
public:Base(){};virtual void Show(){cout<<"This is Base calss";}
};
class Derived:public Base
{
public:Derived(){};void Show(){cout<<"This is Derived class";}
};
int main()
{    //这是第一种情况Base* base = new Derived;if(Derived *der= dynamic_cast<Derived*>(base)){cout<<"第一种情况转换成功"<<endl;der->Show();cout<<endl;}//这是第二种情况Base * base1 = new Base;if(Derived *der1 = dynamic_cast<Derived*>(base1)){cout<<"第二种情况转换成功"<<endl;der1->Show();}else {cout<<"第二种情况转换失败"<<endl;}delete(base);delete(base1);system("pause");
}

运行结果:

      

dynamic_cast和引用类型

在前面的例子中,使用了dynamic_cast将基类指针转换为派生类指针,也可以使用dynamic_cast将基类引用转换为派生类引用。

同样的,引用的向上转换总是安全的:

    Derived c;Derived & der2= c;Base & base2= dynamic_cast<Base&>(der2);//向上转换,安全base2.Show();

所以,在引用上,dynamic_cast依旧是常用于“安全的向下转型”。与指针一样,引用的向下转型也可以分为两种情况,与指针不同的是,并不存在空引用,所以引用的dynamic_cast检测失败时会抛出一个bad_cast异常:

int main()
{    //第一种情况,转换成功Base &base1 = new Derived;Derived &der1 = dynamic_cast<Derived&>(base1);cout<<"第一种情况:";der1.Show();cout<<endl;//第二种情况Base &base = new Base ;cout<<"第二种情况:";try{Derived & der = dynamic_cast<Derived&>(base);}catch(bad_cast){cout<<"转化失败,抛出bad_cast异常"<<endl;}system("pause");
}

运行结果:

使用dynamic_cast转换的Base类至少带有一个虚函数

当一个类中拥有至少一个虚函数的时候,编译器会为该类构建出一个虚函数表(virtual method table),虚函数表记录了虚函数的地址。如果该类派生了其他子类,且子类定义并实现了基类的虚函数,那么虚函数表会将该函数指向新的地址。虚表是C++多态实现的一个重要手段,也是dynamic_cast操作符转换能够进行的前提条件。当类没有虚函数表的时候(也即一个虚函数都没有定义),dynamic_cast无法使用RTTI,不能通过编译(个人猜想...有待验证)。

  当然,虚函数表的建立对效率是有一定影响的,构建虚函数表、由表查询函数 都需要时间和空间上的消耗。所以,除了必须声明virtual(对于一个多态基类而言),不要轻易使用virtual函数。对于虚函数的进一步了解,可以查看《Effective C++》


2、const_cast

const_cast转换过程中增加或删除const属性。

class Test{};
const Test *t1 = new Test;
Test *t2 = const_cast<Test*>(t1);      //转换成功除了添加或删除const特性,用const_cast符来执行其它类型转换,都会引起

编译错误。


3、static_cast

static_cast可以完全替代c的类型转换,而且在对对象指针之间的类型转换时,可以将父类指针转换成子类指针,也可以将子类指针转换成父类指针,但是如果两个类不相关则无法相互转换。 需注意的是,如果父类指针指向一个父类对象,此时将父类指针转换成子类指针虽然可以通过static_cast实现,但是这种转换很不安全;如果父类指针本身就指向子类指针则不存在安全问题。

class Base(){};
class Derived:public Base{};Base *b1 = new Base;
Base *b2 = new Derived;Derived *b2d1 = static_cast<Derived*>(b1);   //转换成功不安全
Derived *b2d2 = static_cast<Derived*>(b2);    //转换成功安全int i = 0;
double d = 1.9;int d2i = static_cast<int>d;
double i2d = static_cast<double>i;

编译器隐式执行的任何类型转换都可以由static_cast显式完成:

当需要将一个较大的算术类型赋值给较小的类型时,使用强制类型转换非常有效。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不关心潜在的精度损失。对于从一个较大的算术类型到一个较小类型的赋值,编译器通常会产生警告。当显示提供强制类型转换时,警告信息会被关闭。

编译器隐式执行的任何类型转换都可以由 static_cast 显式完成:
double d = 97.0;
// cast specified to indicate that the conversion is intentional
char ch = static_cast<char>(d);

如果编译器不提供自动转换,使用 static_cast 来执行类型转换也是很有用的。例如,下面的程序使用 static_cast 找回存放在 void* 指针中的值:

void* p = &d; // ok: address of any data object can be stored in a void*
// ok: converts void* back to the original pointer type
double *dp = static_cast<double*>(p);

可通过 static_cast 将存放在 void* 中的指针值强制转换为原来的指针类型,此时我们应确保保持指针值。也就是说,强制转换的结果应与原来的地址值相等。


4、reinterpret_cast

reinterpret_cast可以将一种类型的指针直接转换成另一种类型的指针,不论两个类型之间是否有继承关系。而且reinterpret_cast可以将一个指针转换为一个整数,也可以把一个整数转换成一个指针。reinterpret_cast还经常用咋不同函数指针之间的转换。

class A{};
class B{};A *a = new A;
B *a2b = reinterpret_cast<B*>(a);     //转换成功

static_cast 运算符完成*相关类型*之间的转换. 而 reinterpret_cast 处理*互不相关的类型*之间的转换.

"互不相关的类型"指的是两种完全不同的类型,如从整型到指针类型,或者从一个指针到另一个毫不相干的指针.

所以 reinterpret_cast 常常被用作不同类型指针间的相互转换,因为所有类型的指针的长度都是一致的(32位系统上都是4字节),按比特位拷贝后不会损失数据.

通常为操作数的位模式提供较低层次的重新解释,reinterpret_cast 本质上依赖于机器。为了安全地使用 reinterpret_cast,要求程序员完全理解所涉及的数据类型,以及编译器实现强制类型转换的细节。
 
例如,对于下面的强制转换:

int *ip;
char *pc = reinterpret_cast<char*>(ip);

变量 pc 所指向的真实对象其实是 int 型,而并非字符数组。任何假设 pc 是普通字符指针的应用,都有可能带来有趣的运行时错误。例如,下面语句用 pc 来初始化一个 string 对象,它可能会引起运行时的怪异行为。

string str(pc);

问题源于类型已经改变时编译器没有提供任何警告或错误提示。当我们用 int 型地址初始化 pc 时,由于显式地声明了这样的转换是正确的,因此编译器不提供任何错误或警告信息。后面对 pc 的使用都假设它存放的是 char* 型对象的地址,编译器确实无法知道 pc 实际上是指向 int 型对象的指针。

因此用 pc 初始化 str 是完全正确的——虽然实际上是无意义的或是错误的。查找这类问题的原因相当困难,特别是如果 ip 到 pc 的强制转换和使用 pc 初始化 string 对象这两个应用发生在不同文件中的时候。


强烈建议:应该避免使用强制类型转换,强制类型转换关闭或挂起了正常的类型检查。

内容资料来源于:

https://blog.csdn.net/pyy18829518070/article/details/80077655

https://www.cnblogs.com/xiangtingshen/p/10851851.html

https://www.cnblogs.com/yshl-dragon/archive/2013/03/22/2975376.html

C++ 四种类型转换操作符相关推荐

  1. C++的四种cast操作符的区别--类型转换

    C++的四种cast操作符的区别 发信站: 水木社区 (Thu Jan 26 21:15:16 2006), 站内 声明 by NetMD: 并非我的原创,来自互联网,且是两篇帖子的合集,个人觉得这样 ...

  2. C++中四种类型转换方式

    C风格的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是:TYPE b = (TYPE)a,但是c 风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型 ...

  3. C++四种cast操作符

    C++的四种cast操作符的区别 发信站: 水木社区 (Thu Jan 26 21:15:16 2006), 站内 声明 by NetMD: 并非我的原创,来自互联网,且是两篇帖子的合集,个人觉得这样 ...

  4. 【C++】类型转换简述:四种类型转换方式的说明及应用

    本文主要简述在C++中四种类型转换的方式:static_cast.reniterpret_cast.const_cast和dynamic_cast. 在介绍C++类型转换方式之前,我们先来看看C语言的 ...

  5. C++4种类型转换操作符

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105112064 类 ...

  6. C++ 四种类型转换

    在写代码中经常会有很多的隐式类型转换或显式类型转换. 对于隐式的类型转换主要是放生在赋值的时候,讲变量赋值给不同类型的变量的时候就会发生类型转换,如果是宽化转换(即从占字节少的类型向占字节多的类型转换 ...

  7. C++/面试 - 四种类型转换(cast)的关键字 详解 及 代码

    四种类型转换(cast)的关键字 详解 及 代码 本文原创, 禁止转载, 如有需要, 请站内联系. 本文地址: http://blog.csdn.net/caroline_wendy/article/ ...

  8. C++四种类型转换总结

    来源:微信公众号「编程学习基地」 文章目录 类型转换 C语言类型转换 C++类型转换 const_cast 去常属性 寄存器骚操作 关键字volatile reinterpret_cast重解释 st ...

  9. c++ 四种类型转换机制

    类型转换机制可以分为:隐式类型转换 和 显示类型转换(强制类型转换) C中的类型转换: 事情要从头说起,这个头就是C语言.我们已经习惯了使用C-like类型转换,因为它强大而且简单. 主要有一下两种形 ...

最新文章

  1. Javascript全局变量和delete
  2. 末日来临,你的编程语言能干嘛? | 每日趣闻
  3. sublime text 2 c++编译 环境 问题小结
  4. ssh配置公钥_如何使用公钥认证免密码ssh远程登录Linux服务器
  5. java 代码发送邮件添加附件_Java实现163邮箱发送邮件到QQ邮箱
  6. 【工业控制】PolyWorks培训教程-PCB字符机平行度和垂直度
  7. mysql union as 注入_sql注入入门 之 mysql 常规注入 [ union方式 ]
  8. lseek函数的使用
  9. layui tree 加载慢_图片太多,加载慢,我用了layui里的方式,放在服务器后还是太慢!怎么解决???有没有什么优化的技巧???...
  10. 关于MQTT协议的说明
  11. 将本地项目上传到Github的两种方式 1.在线上传 2.使用Git客户端上传
  12. ros中使用boost::thread多线程boost::bind绑定参数,多线程发送topic
  13. WKWebView加载HTTPS的链接
  14. json转对象的时候字段为空值的时候会被过滤
  15. p6spy oracle,p6spy简单使用
  16. 如何利用炒股中的L2行情数据功能对比,以及用途数据分析。(附代码)
  17. 从《黑暗森林》到《萤火意志》:外表与内在极度失衡的“艺术品”
  18. 格鲁夫给经理人的第一课
  19. 怎样将本地图片转换成网络链接图片
  20. mongoDB的读书笔记(04)_【Replica】(01)_Replica的一些基本概念

热门文章

  1. CART回归树及其实战
  2. MySql忘记root密码处理方式
  3. Bug的严重程度(Blocker, Critical, Major, Minor/Trivial)和Bug修复优先级如何定义
  4. Linux 添加用户和组
  5. Notepad++ 添加右键菜单
  6. Vue2和vue3diff算法
  7. 前端基础之Html、CSS
  8. 散布矩阵(Scatter Matrix)
  9. 先验概率与后验概率的区别(通俗易懂)
  10. 中国大学MOOC中国传统建筑文化题库(含答案)