c++中的四种cast转换, dynamic_cast、static_cast、const_cast、reinterpret_cast
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相关推荐
- 你真懂吗?C++ 四种 cast 转换
目录 C++11 四种 cast 转换 1.const_cast 2.static_cast 3.dynamic_cast 4.reinterpret_cast typeid C++11 四种 cas ...
- C++中四种 cast 转换
四种 cast 转换 C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast const_cast static_cas ...
- 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+ ...
- 面试准备每日五题:C++(七)——左值右值、面向对象、四种cast转换、拷贝构造函数赋值、虚函数多态
文章目录 一. 什么是右值引用,跟左值又有什么区别? 二. 面向对象的三大特征 三. c++中四种cast转换 四.拷贝构造函数和赋值运算符的认识 五. 对虚函数和多态的理解 一. 什么是右值引用,跟 ...
- C++中四种cast转换
C++中四种类型转换是:static_cast, dynamic_cast, const_cast, reinterpret_cast 1.const_cast 用于将const变量转为非const ...
- c++工程师面试常见问题之c++中四种cast转换
int main() { const int a = 10; // a++; int& b = const_cast<int &>(a); b++; cout <&l ...
- C++四种强制类型转换 dynamic_cast,const_cast,static_cast,reinterpret_cast
综述 dynamic_cast 用于多态类型的转换 static_cast 用于非多态类型的转换 const_cast 用于删除 const.volatile 和 __unaligned 特性 r ...
- c++ dynamic_cast,static_cast,const_cast,reinterpret_cast四种cast用法整理
在C++中主要分为四种cast,分别是:static_cast.dynamic_cast.const_cast和reinterpret_cast dynamic_cast动态类型转换 首先,我们明确基 ...
- C++四种cast操作符
C++的四种cast操作符的区别 发信站: 水木社区 (Thu Jan 26 21:15:16 2006), 站内 声明 by NetMD: 并非我的原创,来自互联网,且是两篇帖子的合集,个人觉得这样 ...
最新文章
- 杨强教授力荐,快速部署落地深度学习应用的实践手册
- 查看并修改mysql的默认引擎
- 嵌入式linux------ffmpeg移植 解码H264(am335x解码H264到yuv420并通过SDL显示)
- ios 一步一步学会自定义地图吹出框(CalloutView)--(百度地图,高德地图,google地图)
- QDoc上下文命令contextcommands
- IOS中扩展机制Category和associative
- 新手如何入门PyTorch
- 8: springMVC ModelAndView 作用与功能解析
- 推荐电影 历年佳片有约电影 1998-2007
- 广东又将添新高校:香山大学来了
- QQ城市达人接口编程及经验分享2--新接口
- celeste第二章_魂源蔚蓝-第二章:源士的力量体系-爱阅小说网
- 人工智能截稿日期重磅
- 前端js正则验证大全(一套完整的正则验证解决方案)@莫成尘
- 1 Flask_FileUpload
- 关于sqlldr官方教材上的几个例子ulcase study1-9
- 用于PCB设计和印刷的修补匠工具
- Crow search algorithm(乌鸦搜索算法)
- 基于 CNT 的射频辐射热计开发研究的 CPX-VF 低温探针台
- Unity全局音量控制以及音量信息存储在本地
热门文章
- docker tag 详解
- jdk配置教程详(sha)细(gua)版
- 【提示学习】Exploiting Cloze Questions for Few Shot Text Classification and Natural Language Inference
- php pinterest,使用PHP解析pinterest JSON api
- 基于单片机智能远程可控交通信号灯系统设计
- 盛夏来一杯温热红茶,淡淡茶香解暑去乏
- centos7 系统优化
- 中国电信业重组方案敲定!——新的格局拭目以待
- i5 1245U怎么样 相当于什么水平
- 30天自制操作系统——第4天实验总结