C++四种强制类型转换运算符

C/C++中的类型转换分为两种:隐式类型转换和显式类型转换。

而对于隐式类型转换,在很多时候,不经意间就发生了,比如int类型和float类型赋值时,int类型就会被隐式的转换位float类型。

举例:

int i = 5;
float d = i;//隐式类型的转换
int* p = (int*)i;//C style,强制类型的转换.

C++对C兼容,所以上述方式的类型转换是可以的,但是有时候会有问题,所以推荐使用C++中的四个强制类型转换的关键字:
static_cast、reinterpret_cast、const_cast 和 dynamic_cast。下面将逐一介绍。

static_cast

这应该四种中是最常见的。用法为:

static_cast < new_type > ( expression ) 		

该运算符把 expression 转换为new_type 类型。

特点:

1、 用于非多态类型的转换
2、 不执行运行时类型检查(转换安全性不如 dynamic_cast)
3、通常用于转换数值数据类型(如 float -> int)
4、 可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法)

通常用于转换数值数据类型(如 float -> int):


#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
	
	float f = 4.5;
	int a = f; //C-style

	int b = static_cast<int>(f);
	cout << b << endl;

	return 0;
}

编译输出:

在这里插入图片描述
现在让我们对代码做一些修改:

#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
	
	int a = 10;
	char c = 'a';

	
	int* q = (int*) &c;
	int *p = static_cast<int *>(&c);//编译错误,static_cast 不能将字符转换成指针

	return 0;
}

编译:
在这里插入图片描述

这意味着,即使您认为可以将特定对象类型转换为另一个对象,但这是非法的,static_cast也不允许这样做。

static_cast 用于基本数据类型之间的转换,如把int转换成char,把int转换成float。在c++ primer 中说道:c++ 的任何的隐式转换都是使用 static_cast 来实现。

让我们以继承为例,来看看这个例子:


#include <iostream>
using namespace std;

class Base { 

}; 
class Derived : public Base { 

}; 

int main(int argc, char const *argv[])
{
	
    Derived d1; 
    Base* b1 = (Base*)(&d1); // 允许 
    Base* b2 = static_cast<Base*>(&d1); 

	return 0;
}


编译:
在这里插入图片描述编译,上面的代码将不会出现任何错误。
1、我们取&d1,显式的存入Base中,存储在b1中。
2、我们取&d1,用static_cast将其转换成Base,存储在b2中。

我们知道static_cast执行严格的类型检查,让我们稍微修改一下代码看看,把继承改为private。


#include <iostream>
using namespace std;

class Base { 

}; 
class Derived :  private Base { 

}; 

int main(int argc, char const *argv[])
{
	
    Derived d1; 
    Base* b1 = (Base*)(&d1); // 允许 
    Base* b2 = static_cast<Base*>(&d1); 

	return 0;
}

编译:
在这里插入图片描述即使继承为受保护的,上面的代码也不会编译。因此,要使用static_cast,请将其继承为public。

使用static_cast将“向空指针”和“从空指针”进行强制转换。例子:


#include <iostream>
using namespace std;

int main(int argc, char const *argv[])
{
	
    int i = 10; 
    void* v = static_cast<void*>(&i); 
    int* ip = static_cast<int*>(v); 

	return 0;
}

编译:
在这里插入图片描述
const_cast

用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 )

const_cast可用于更改const成员函数内的非const类成员。考虑以下代码片段。

#include <iostream>
using namespace std;

class student 
{ 
private: 
    int roll; 
public: 
    // 构造函数
    student(int r):roll(r) {} 
  
    // 在const_cast的帮助下改变roll的const函数
    void fun() const
    { 
        ( const_cast <student*> (this) )->roll = 5; 
    } 
  
    int getRoll()  { return roll; } 
}; 

int main(int argc, char const *argv[])
{
	
    student s(3); 
    cout << "Old roll number: " << s.getRoll() << endl; 
  
    s.fun(); 
  
    cout << "New roll number: " << s.getRoll() << endl; 
  
	return 0;
}

编译输出:
在这里插入图片描述

在const成员函数fun()中,编译器将“ this”视为“ const student * const this”,即“ this”是指向常量对象的常量指针,因此编译器不允许通过以下方式更改数据成员“这个”指针。const_cast将“ this”指针的类型更改为“ student * const this”。

const_cast可用于将const数据传递给不接收const的函数。例如:


#include <iostream>
using namespace std;


int fun(int* ptr) 
{ 
    return (*ptr + 10); 
} 
int main(int argc, char const *argv[])
{
	
    const int val = 10; 
    const int *ptr = &val; 
    int *ptr1 = const_cast <int *>(ptr); 
    cout << fun(ptr1)<<endl; 


	return 0;
}

编译输出:
在这里插入图片描述
const_cast比简单类型转换更安全。从某种意义上讲,如果强制类型与原始对象不相同,则强制强制转换不会发生,这是比较安全的。例如:

#include <iostream>
using namespace std;

int main(int argc, char const *argv[])
{
	
    int a1 = 40; 
    const int* b1 = &a1; 
    char* c1 = const_cast <char *> (b1); // 编译程序时出错
    *c1 = 'A'; 

	return 0;
}

编译:
在这里插入图片描述
程序编译失败,因为将“ int *”类型转换为“ char *”

const_cast也可以用来抛弃volatile属性。例如:


#include <iostream>
#include <typeinfo>  // typeid
using namespace std;

int main(int argc, char const *argv[])
{
	
    int a1 = 40; 
    const volatile int* b1 = &a1; 
    cout << "typeid of b1 " << typeid(b1).name() << '\n'; 
    int* c1 = const_cast <int *> (b1); 
    cout << "typeid of c1 " << typeid(c1).name() << '\n'; 

	return 0;
}


编译输出:
在这里插入图片描述在程序中,b1的typeid是PVKi(指向易失性和整数的指针),而c1的typeid是Pi(指向整数的指针)。

reinterpret_cast

reinterpret_cast是C ++中使用的一种强制转换运算符。

它用于转换任何类型的另一个指针的一个指针,而不管该类是否相互关联。
它不检查指针类型和指针所指向的数据是否相同。

用法如下:

reinterpret_cast <数据类型*>(指针变量);

来看看 reinterpret_cast 简单用法:


#include <iostream>
using namespace std;

int main(int argc, char const *argv[])
{
	
    int* p = new int(65); 
    char* ch = reinterpret_cast<char*>(p); 
    cout << *p << endl; 
    cout << *ch << endl; 
    cout << p << endl; 
    cout << ch << endl; 

	return 0;
}

在这里插入图片描述
使用reinterpret_cast的目的:

1、reinterpret_cast是一种非常特殊且危险的类型转换操作符。并且建议使用适当的数据类型使用它,即(指针数据类型应与原始数据类型相同)。

2、它可以将任何指针类型转换为任何其他数据类型。

3、当我们要使用位时使用它。

4、它仅用于将任何指针转换为原始类型。

5、布尔值将转换为整数值,即0表示false,1表示true。

来看看下面一个例子:


#include <iostream>
using namespace std;


// 创建结构体mystruct
struct mystruct { 
    int x; 
    int y; 
    char c; 
    bool b; 
}; 



int main(int argc, char const *argv[])
{
	
    mystruct s; 
  
    // 结构体赋值
    s.x = 5; 
    s.y = 10; 
    s.c = 'a'; 
    s.b = true; 
  
    // 在强制转换期间,数据类型必须与原始数据类型相同
  
    // 将's'指针转换为'p'中int类型的指针。
    
    int* p = reinterpret_cast<int*>(&s); 
  
    cout << sizeof(s) << endl; 
  
    // 打印当前由*p指向的值
    cout << *p << endl; 
  
    // 将指针增加1
    p++; 
  
    // 打印下一个整数值
    cout << *p << endl; 
  
    p++; 
  
    // 用char *ch将char *指向p。
    // 
    char* ch = reinterpret_cast<char*>(p); 
  
    // 打印(*ch)指定的字符值
    cout << *ch << endl; 
  
    ch++;  
  
    bool* n = reinterpret_cast<bool*>(ch); 
    cout << *n << endl; 
  
    cout << *(reinterpret_cast<bool*>(ch)); 

	return 0;
}


编译输出:

在这里插入图片描述
再看一个例子:


#include <iostream>
using namespace std;

class A { 
public: 
    void fun_a() 
    { 
        cout << " In class A\n"; 
    } 
}; 
  
class B { 
public: 
    void fun_b() 
    { 
        cout << " In class B\n"; 
    } 
}; 


int main(int argc, char const *argv[])
{
	
    // 创建B类的对象
    B* x = new B(); 
  
    // 将指向B类引用的对象的指针转换为A类
    A* new_a = reinterpret_cast<A*>(x); 
  
    // 访问A类的函数。
    new_a->fun_a(); 
    return 0; 
}


编译输出:

在这里插入图片描述
dynamic_cast

dynamic_cast的转换格式:

dynamic_cast <type-id> (expression)

将expression转换为type-id类型,type-id必须是类的指针、类的引用或者是void *;如果type-id是指针类型,那么expression也必须是一个指针;如果type-id是一个引用,那么expression也必须是一个引用。

最简单的上行转换,比如Derived 继承自Basic,Derived 转换为Basic,进行上行转换时,是安全的,如下:

#include <iostream>
using namespace std;
 
class Basic{
     public:
          virtual int test(){return 0;}  // 必须为多态以使用运行时检查的 dynamic_cast
};
 
class Derived : public Basic{

     public:
          int test(){return 1;}
};
 
int main(int argc, char const *argv[]){
     Basic      cBasic;
     Derived    cDerived;
     
     Basic * pB1 = new Basic;
     Basic * pB2 = new Derived;
 
     //动态强制转换失败,因此pD1为空。
     Derived * pD1 = dynamic_cast<Derived * > (pB1);   
                 
 
     //动态强制转换成功,因此rD2引用派生对象。
     Derived & rD2 = dynamic_cast<Derived &> (*pB2);   
 
     return 0;
} 

编译:

在这里插入图片描述
参考:static_cast in C++ | Type Casting operators
reinterpret_cast in C++ | Type Casting operators
const_cast in C++ | Type Casting operators
在这里插入图片描述
(微信公众号【程序猿编码】)

在这里插入图片描述
(添加本人微信号,备注加群,进入程序猿编码交流群,领取学习资料,获取每日干货)

微信公众号【程序猿编码】,这里Linux c/c++ 、Python、Go语言、数据结构与算法、网络编程相关知识,常用的程序员工具。还有汇聚精炼每日时政、民生、文化、娱乐新闻简报,即刻知晓天下事!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值