C++11之后,C++中就有四种类型转换,分别是 dynamic_cast、static_cast、const_cast、reinterpret_cast,一般用这四种强制转换可以替代在c代码中类似(int)这种方式的转换。下面就分别对着四种强制转换进行介绍以及使用方法。

dynamic_cast

主要是用于有继承关系的,或者说实现存在多态的父类和子类之间的转换。如果两个类是继承关系,但是没有多态的存在(也就是没有虚函数),那么使用dynamic_cast进行转换,编译器会报错的,例如如下代码:

#include<iostream>
using namespace std;class Base  // 父类
{};class Child :public Base { // 子类};int main()
{Base* b_ptr = new Child();Child* c_ptr = dynamic_cast<Child*>(b_ptr); //这里会报错,在vs2019中,提示:运行时 dynamic_cast// 的操作数必须包含多态类类型}

在没有多态类类型的转换中,编译器会提示报错。
dynamic_cast主要是用在进行下行转换(父类转换到子类)过程中的安全判定,上行转换(也就是子类转换为父类一定是安全的,例如下面代码中的情况3);如果出现一些不安全的转换,则返回值就是nullptr,例如下面代码中的情况2;下行转换什么情况下是安全的呢?例如,当父类指针指向子类对象时,然后将这个父类指针利用dynamic_cast转换为子类,这种情况是安全的,因为这个指针指向的对象就是子类,例如下面代码中的情况2。

dynamic_cast应用示例代码

#include<iostream>
using namespace std;class Base  // 父类
{public:virtual void f(){cout << "this is base class !" << endl;}
};class Child :public Base { // 子类
public:void f(){cout << "this is child class !" << endl;}};int main()
{//情况1Base* b_ptr0 = new Base(); // 指向父类的父类指针Child* c_ptr0 = dynamic_cast<Child*>(b_ptr0);// 下行转换,此时由于父类指针实际上是指向父类的,//这个转换不安全,所以c_ptr0的值为nullptrif (!c_ptr0){cout << "can not cast the type !" << endl; // 代码会走到这里}else{c_ptr0->f();}//情况2Base* b_ptr = new Child();// 指向子类的父类指针Child* c_ptr = dynamic_cast<Child*>(b_ptr); // 下行转换,此时由于父类指针实际上是指向子类的//所以这个转换是可以的if (!c_ptr){cout << "can not cast the type !" << endl;}else{c_ptr->f();// 代码会走到这里}//情况3Child* c_ptr1 = new Child();// 指向子类的子类指针Base* b_ptr1 = dynamic_cast<Base*>(c_ptr1); // 将子类转换为父类是安全的,上行转换一定是允许的if (!b_ptr1){cout << "can not cast the type !" << endl;}else{b_ptr1->f();// 代码会走到这里}/** 输出是* can not cast the type !* this is child class !* this is child class !* */}

static_cast

这种静态转换可以实现很多dynamic不能实现的,没有安全检查,
不能实现

  • 不相关类之间的转换,例如下述代码的eg1

可以实现:

  • 继承父类和子类之间的上行转换和下行转换,不保证安全,例如下述代码的eg2
  • 能够进行void * 到其他指针的任意转换,例如下述代码的eg3
  • 能够将 int float double以及枚举类型的转换,例如下述代码的eg4
  • 实现转换到右值引用,例如下述代码的eg5

static_cast应用示例代码

#include<iostream>
using namespace std;class Other
{};class Base  // 父类
{public:virtual void f(){cout << "this is base class !" << endl;}
};class Child :public Base { // 子类
public:int a = 10;string b = string("asd");void f(){cout << "this is child class !" << endl;}void CFun(){cout << "the first string is " << b[1] << endl;cout << "the value of  a in " << a << endl;}};enum class Fruit {Anple, Oringe, Banana, Watermelon};int main()
{//eg 1 不能进行不相关类之间的转换,例如 Other与BaseOther* o = new Other();Base* b = static_cast<Base*>(o); // faild,这里会报错//eg 2 能够进行上行转换(upcast)和下行转换(downcast),不保证安全,需要程序员自己去保证安全Base* b1 = new Base();Child* c1 = new Child();Child* c11 = static_cast<Child*>(b1);// 下行转换,不安全,需要程序员自己保证//c11->CFun(); // failed 这里调用CFun,由于基类里面没有对应a变量和b变量,所以肯定会报错Base* b11 = static_cast<Base*>(c1); // 上行转,安全//eg 3 能够进行void * 到其他指针的任意转换void* p = nullptr;Base* b2 = static_cast<Base*>(p); // 这里是将void * 转换为 Base*void* p1 = static_cast<void*>(b1); // 这里是将Base* 转换为 void *// eg4 能够将 int float double以及枚举类型的转换Fruit f = Fruit::Anple;int i_value = static_cast<int>(f);Fruit ff = static_cast<Fruit>(3); // 将整数3转换为Fruit::Watermelonint i_val = 100;double d_val = 1.000;float f_val = 2.000;int i_value1 = static_cast<int>(d_val); // double 向 int 进行转换int i_value2 = static_cast<int>(f_val); // float 向 int 进行转换float f_val1 = static_cast<float>(i_val);// int 向 double 进行转换double d_val1 = static_cast<double>(i_val);// int 向 float 进行转换// eg5 实现转换到右值引用int&& left_val = static_cast<int&&>(5); // 将左值转换为右值,和std::move功能差不多}

const_cast

主要是用来去除复合类型中const属性,例如如下代码:

#include <iostream>
#include <stdio.h>using namespace std;void fun(int* a)
{cout << *a << endl;
}int main()
{int a = 10;const int* a_ptr = &a;//fun(a_ptr); // failed, 参数类型不对,需要非const 类型的参数fun(const_cast<int*>(a_ptr)); // success,转换为非const 类型的参数,可以进行函数调用return 0;
}

在我们自定义的类中,去除const属性之后,可以修改原来的值,一般是通过转换为指针或者引用进行修改,例如下述示例:

#include <iostream>
#include <stdio.h>using namespace std;void fun(int* a)
{cout << *a << endl;
}class myClass
{public:int a = 10;
};int main()
{const myClass* c = new myClass();cout << c->a << endl;//c->a = 100; // failed,const常量不能修改myClass* cc = const_cast<myClass*>(c);cc->a = 100; // successcout<< c->a <<" "<<cc->a<< endl;return 0;
}

但是,上面强调了自定义的类,如果不是自定义类,比如整数,字符串指针等,就会有意想不到的报错或者奇怪现象,例如:
eg1:

#include <iostream>
#include <stdio.h>using namespace std;int main()
{const char * s = "asd asd";char * ss = const_cast<char *>(s);ss[1] = '1'; // 这里会报错,cout << s << '\n' << ss << endl;return 0;}

eg2:
借鉴了这篇文章,解释的挺清晰的

#include <iostream>
using namespace std;int main () {const int data = 100;int *pp = (int *)&data;*pp = 300;cout << "data = " << data << "\t地址 : " << &data << endl << endl ;cout << "  pp  = " << *pp << "\t地址 : " << pp << endl << endl ;int *p = const_cast<int*>( &data ) ;cout << "data = " << data << "\t地址 : " << &data << endl << endl ;cout << "  p  = " << *p << "\t地址 : " << p << endl << endl ;*p = 200 ;cout << "data = " << data << "\t地址 : " << &data << endl << endl ;cout << "  p  = " << *p << "\t地址 : " << p << endl << endl ;return 0 ;
}

输出是

很奇怪? data 的地址是 0x6ffdfc, p 指向的地址也是 0x6ffdfc, 但是修改 p 之后, 同一个地址上的内容却不相同。
可能是 const 的问题? const 的机制,就是在编译期间,用一个常量代替了 data。这种方式叫做常量折叠。
常量折叠与编译器的工作原理有关,是编译器的一种编译优化。在编译器进行语法分析的时候,将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。所以在上面的例子中,编译器在优化的过程中,会把碰到的data(为const常量)全部以内容100替换掉,跟宏的替换有点类似。常量折叠只对原生类型起作用,对我们自定义的类型,是不会起作用的。

不过通常我们用到的一般会是修改自己定义的类,如果是原生类型,一般的操作也不会去修改对应的数据,大多数只是作为传参数而已。

reinterpret_cast

相比于static_cast,reinterpret_cast功能更强大,安全性更低,对程序员的要求就会更高一些,它可以实现

  • 相关类型之间的转换,例如两个完全没有关系的类A和B,例如下述示例代码的eg1;
  • 可以实现指针和整数之间的转换,例如下述示例代码的eg2;
#include<iostream>
using namespace std;class Other
{};class Base  // 父类
{public:virtual void f(){cout << "this is base class !" << endl;}
};class Child :public Base { // 子类
public:int a = 10;string b = string("asd");void f(){cout << "this is child class !" << endl;}void CFun(){cout << "the first string is " << b[1] << endl;cout << "the value of  a in " << a << endl;}};int main()
{//eg 1 可以进行不相关类之间的转换,例如 Other与BaseOther* o = new Other();Base* b = reinterpret_cast<Base*>(o); //eg 2 指针和整数进行转换int i_val = 100;int* i_ptr = &i_val;int reinterpret_val = reinterpret_cast<int>(i_ptr); // 将整数指针转换为整数cout << reinterpret_val << endl;int* i_ptr1 = reinterpret_cast<int *>(reinterpret_val); // 将整数转换为整数指针cout << *i_ptr1 << endl;Base* b1 = new Base();int reinterpret_val1 = reinterpret_cast<int>(b1); // 将Base指针转换为整数cout << reinterpret_val1 << endl;Base* b2 = reinterpret_cast<Base*>(reinterpret_val1); // 将对应整数转换为Base指针b2->f(); // 输出this is base class !}

总结

  • dynamic_cast主要用在存在多态类的转换,用于保证安全转换。
  • static_cast不能进行不相关类之间的转换可以实现上行转换和下行转换;继承父类和子类之间的上行转换和下行转换,不保证安全;能够进行void * 到其他指针的任意转换;能够将 int float double以及枚举类型的转换;实现转换到右值引用;
  • const_cast通常用作去除变量的const属性,对于原生类型,修改对应的值可能比较麻烦,但是对于大部分类型,是可以进行修改的,一般是通过转换为指针或者引用进行修改;
  • reinterpret_cast主要用在两个完全没有联系的类型之间的转换,可以实现指针和整数之间的转换;

c++中的四种cast转换, dynamic_cast、static_cast、const_cast、reinterpret_cast相关推荐

  1. 你真懂吗?C++ 四种 cast 转换

    目录 C++11 四种 cast 转换 1.const_cast 2.static_cast 3.dynamic_cast 4.reinterpret_cast typeid C++11 四种 cas ...

  2. C++中四种 cast 转换

    四种 cast 转换 C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast const_cast static_cas ...

  3. C++四种cast转换(const_cast、static_cast、dynamic_cast、reinpreter_cast)类型转换运算符

    文章目录 cast含义 C++四种类型转换符各自应用场景(简略) 1. static_cast 2. dynamic_cast 3. reinterpret_cast 4. const_cast C+ ...

  4. 面试准备每日五题:C++(七)——左值右值、面向对象、四种cast转换、拷贝构造函数赋值、虚函数多态

    文章目录 一. 什么是右值引用,跟左值又有什么区别? 二. 面向对象的三大特征 三. c++中四种cast转换 四.拷贝构造函数和赋值运算符的认识 五. 对虚函数和多态的理解 一. 什么是右值引用,跟 ...

  5. C++中四种cast转换

    C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast 1.const_cast 用于将const变量转为非const ...

  6. c++工程师面试常见问题之c++中四种cast转换

    int main() { const int a = 10; // a++; int& b = const_cast<int &>(a); b++; cout <&l ...

  7. C++四种强制类型转换 dynamic_cast,const_cast,static_cast,reinterpret_cast

    综述 dynamic_cast  用于多态类型的转换 static_cast 用于非多态类型的转换 const_cast  用于删除 const.volatile 和 __unaligned 特性 r ...

  8. c++ dynamic_cast,static_cast,const_cast,reinterpret_cast四种cast用法整理

    在C++中主要分为四种cast,分别是:static_cast.dynamic_cast.const_cast和reinterpret_cast dynamic_cast动态类型转换 首先,我们明确基 ...

  9. C++四种cast操作符

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

最新文章

  1. 杨强教授力荐,快速部署落地深度学习应用的实践手册
  2. 查看并修改mysql的默认引擎
  3. 嵌入式linux------ffmpeg移植 解码H264(am335x解码H264到yuv420并通过SDL显示)
  4. ios 一步一步学会自定义地图吹出框(CalloutView)--(百度地图,高德地图,google地图)
  5. QDoc上下文命令contextcommands
  6. IOS中扩展机制Category和associative
  7. 新手如何入门PyTorch
  8. 8: springMVC ModelAndView 作用与功能解析
  9. 推荐电影 历年佳片有约电影 1998-2007
  10. 广东又将添新高校:香山大学来了
  11. QQ城市达人接口编程及经验分享2--新接口
  12. celeste第二章_魂源蔚蓝-第二章:源士的力量体系-爱阅小说网
  13. 人工智能截稿日期重磅
  14. 前端js正则验证大全(一套完整的正则验证解决方案)@莫成尘
  15. 1 Flask_FileUpload
  16. 关于sqlldr官方教材上的几个例子ulcase study1-9
  17. 用于PCB设计和印刷的修补匠工具
  18. Crow search algorithm(乌鸦搜索算法)
  19. 基于 CNT 的射频辐射热计开发研究的 CPX-VF 低温探针台
  20. Unity全局音量控制以及音量信息存储在本地

热门文章

  1. docker tag 详解
  2. jdk配置教程详(sha)细(gua)版
  3. 【提示学习】Exploiting Cloze Questions for Few Shot Text Classification and Natural Language Inference
  4. php pinterest,使用PHP解析pinterest JSON api
  5. 基于单片机智能远程可控交通信号灯系统设计
  6. 盛夏来一杯温热红茶,淡淡茶香解暑去乏
  7. centos7 系统优化
  8. 中国电信业重组方案敲定!——新的格局拭目以待
  9. i5 1245U怎么样 相当于什么水平
  10. 30天自制操作系统——第4天实验总结