C/C++类型转换:reinterpret_cast、const_cast、dynamic_cast、static_cast

先说C语言类型转换,在c语言中,存在两种类型转换,一种是隐式类型转换,另一种是显示类型转换。并且这种转换只允许基类型,也就是如char,short,int,long,float,double ,或者指针),而不允许用于struct,union等类型。
如下:

int    a = 5;
double b = a;     /* 隐式类型转换,类型相近。 */

int *ptr = &a;
int ptr_value = (int) ptr; /* 显示类型转换,两者类型不相干。 */

C++为了增强转换的可视性,引入了四种强制转换的操作符分别是static_cast、const_cast、dynamic_cast、reinterpret_cast。

一、static_cast

static_cast <type-id>(expression):将expression转换为type-id 类型
最常用的类型转换,常常用于数值型类型之间的类型转换,功能与C语言中的强制类型转换相似,处理隐式类型转换。但它不能用于两个不相关的类型之间的转换,而且无运行时类型检查,转换存在不安全性。
 

/* 相关类型的转换 */
int a = 10;
double b = static_cast<double>(a);

int a = 10;
char c = static_cast<char>(a); /* 不保证安全,得到的char可能没有足够的位来保存整个int值,那么就需要程序员来验证static_cast转换的结果是否安全。*/

static_cast相当于传统的C语言里的强制转换,其实可以完全替代C语言中强制转换,该运算符把expression转换为new_type类型,用来强迫隐式转换如non-const对象转为const对象,编译时检查,用于非多态的转换,可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:

 

  1. 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。

进行上行转换(把派生类的指针或引用转换成基类表示)是安全的

进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的

  1. 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。
  2. 把空指针转换成目标类型的空指针。
  3. 把任何类型的表达式转换成void类型。

注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性

基本类型数据转换举例如下:

char a = 'a';
int b = static_cast<int>(a);//正确,将char型数据转换成int型数据
double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针
int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据
const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性

类上行和下行转换:

class Base  //基类
{};

class Derived : public Base //派生类
{}

Base* pB = new Base();
if(Derived* pD = static_cast<Derived*>(pB))
{}//下行转换是不安全的(坚决抵制这种方法)

Derived* pD = new Derived();

if(Base* pB = static_cast<Base*>(pD))
{}//上行转换是安全的

二、reinterpret_cast:重新解释类型


reinterpret_cast<type-id>(expression):
1.一般用于不相关类型变量之间的转换,相当于C语言中的显示强制类型转换。
2.一般用于用于非多态的类型转换(静态转换)。

/* 不相关类型的转换 */
int a = 10;
int* p = &a;
int b = reinterpret_cast<int>(p);

int a = 0x018bc597ac;/*假设这是一个合法的地址*/
int* p = static_cast<int*>(a);    /* 失败   error:   invalid static_cast from type ‘int’ to type ‘int*’  */
int* p = reinterpret_cast<int*>(a); /* 成功   warning: overflow in implicit constant conversion [-Woverflow]*/	

在这里类型转换使用中常用来将void * 地址转为相对应的类型地址。使用是一定要是一个合法的地址

三、const_cast


const_cast<type-id>(expression):从类中移除const、volatile和__unaligned特性。

	const int a = 10;
	int *p = &a;/* error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]  */
	*p = 20;
	cout << "a = " << a << endl; 
	cout << "*p = " << *p << endl; 

#if 0
	
	int* p = const_cast<int*>(&a);//&a的类型:const int*/int const*
	*p = 20;
	cout << "a = " << a << endl;  //a = 10
	cout << "*p = " << *p << endl; //*p = 20
	
#endif


volatile const int i = 10;
int* j = const_cast<int*>(&i);//&a的类型:const int*/int const*
*j = 20;
cout << i << endl;//20
cout << *j << endl;//20

四、dynamic_cast


dynamic_cast<type-id>(expression)
1.用于将一个父类对象的指针或引用转换为子类对象的指针或引用(动态转换)。
2.涉及继承,只能用于包含虚函数构成多态的类,不是虚函数会报错。
3.dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。

#include<stdio.h>
#include <iostream>

using namespace std;

class A
{
public:
	int A_a;
 
	virtual void f()
	{}
};
class B :public A
{
public:
	int B_b;
};

void test_fun(A* pa)
{
    //使用static_cast转换:如果是派生类指针转换则没问题;
    //如果是基类指针通过强制转换虽然会成功,但是可能会造成越界访问的问题,因为这个是简单的强制转换
	//没有类型检测机制
	B* pb1 = static_cast<B*>(pa);
	cout << "pb1:" << pb1 << endl;
	//pb1->_b=20;/* error: ‘class B’ has no member named ‘_b’ */
	
    //使用dynamic_cast转换:如果是派生类指针转换则没问题;
    //如果是基类指针则转换失败,返回0;因为类型检测失败,
	B* pb2 = dynamic_cast<B*>(pa);
	cout << "pb2:" << pb2 << endl;
}

int main()
{	
	cout << "Hello CPP" << endl;
	
	A a;
	B b;
	test_fun(&a);//传递基类对象----->小范围对象内存空间:可能会造成内存访问越界
	test_fun(&b);//传递派生类对象--->大范围对象内存空间
	
	return 0;
}

dynamic_cast< type* >(e)

 type必须是一个类类型且必须是一个有效的指针 

dynamic_cast< type& >(e)

type必须是一个类类型且必须是一个左值也就是说是一个非const修饰的左值

dynamic_cast< type&& >(e)

type必须是一个类类型且必须是一个右值,不能是左值

 

e的类型必须符合以下三个条件中的任何一个: 

1、e的类型是目标类型type的公有派生类 

2、e的类型是目标type的共有基类 

3、e的类型就是目标type的类型。

 

如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。

e也可以是一个空指针,结果是所需类型的空指针。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换(cross cast)。

 

上行转换

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;

下行装换

在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。

 

1指针类型转换

举例,Base为包含至少一个虚函数(virtual修饰的函数)的基类,Derived是Base的共有派生类,如果有一个指向Base的指针bp,我们可以在运行时将它转换成指向Derived的指针,代码如下:

Base *bp = new Base();

if(Derived *dp = dynamic_cast<Derived *>(bp)){
  //使用dp指向的Derived对象  
}
else{
  //使用bp指向的Base对象  
}

值得注意的是,在上述代码中,if语句中定义了dp,这样做的好处是可以在一个操作中同时完成类型转换和条件检查两项任务。

 

2. 引用类型

因为不存在所谓空引用,所以引用类型的dynamic_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad_cast异常,该异常定义在头文件typeinfo中。

void f(const Base &b){
   try{
      const Derived &d = dynamic_cast<const Base &>(b);  
      //使用b引用的Derived对象
   }catch(std::bad_cast){
      //处理类型转换失败的情况
   }
}

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值