目录
前言:
C++为了规范强制类型转换的可观性与安全性,引入了4种强制类型转换符,他们分别是:static_cast、reinterpret_cast、const_cast、dynamic_cast。
1、C++新增转换符的原因
因为c语言的类型转换存在一些缺点,虽然c语言的转换风格简单易懂,但是有些场景下会导致数据精度的丢失不易被发现,即隐式类型转换的代码可读性不强, 而显示类型转换(强制转换)可以让多种类型之间相互转换,不够规范。
2、类型转换的概念
由于C++兼容c语言,因此C++对类型转换的概念是沿用c语言的概念,只不过在其基础上做了优化,当两个对象之间发生了赋值或拷贝,而这两个对象的类型又不一样,就会发生类型转换,并且转换的类型是以被执行对象的类型为基准进行转换,比如赋值运算符的左右两侧类型不相同,或者函数的实参传给形参的类型不相同,又或者函数返回值与接收值类型不相同,这些场景下都会发生类型转换。
c语言对类型转换有两种定义:
1、隐式类型转换、即两个转换对象的类型不一样,让编译器完成他们之间转换,若他们之间不能转换则会报错。
2、显示类型转换、又称强制类型转换,由程序员手动干预转换过程,通常在执行对象的前面加小括号,小括号里写转换之后的类型。
类型转换测试代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
int i = 12;
// 隐式类型转换
double d = i;
printf("%d, %f\n", i, d);
int* p = &i;
// 显示的强制类型转换
int address = (int)p;
printf("%x, %d\n", p, address);
return 0;
}
运行结果:

转换过程细节图:

3、C++强制类型转换
3.1 static_cast
static_cast的效果类似上文提到的隐式类型转换,只不过他可以提高代码的可读性,让程序员一眼就可以看出转换之后的类型,具体示例如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
double d = 3.141596;
int a = static_cast<int>(d);//static_cast的用法,<>中表示转换后的类型
cout << a << endl;
return 0;
}
运行结果:

值得注意的是, static_cast不支持两种毫不相干的类型进行转换,比如int类型不能转换为string类型,如下图:

3.2 reinterpret_cast
reinterpret_cast可以将位操作数上意义近似的两种不相关的类型进行转换,他带有“重新解释”的意思,比如将int类型转换为指针类型,示例代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
int a = 12;
int* p = reinterpret_cast<int*>(a);
cout << p << endl;
// 这里使用static_cast会报错
//int *p = static_cast<int*>(a);
return 0;
}
运行结果:

但是reinterpret_cast同样不能将int类型转换为string类型。
3.3 const_cast
const_cast可以让一个被const修饰的变量去掉其const的属性,即可以对该变量赋值。注意:const_cast的<>中只能是指针或引用,即const_cast转换后的类型只能是指针或引用。
测试代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
//若不加volatile,则修改的寄存器中的a,并不是内存中的a
volatile const int a = 2;
int* rp = const_cast<int*>(&a);//去掉了a的const,则可以通过指针修改他
*rp = 3;
cout << a << endl;
cout << *rp << endl;
return 0;
}
运行结果:

值得注意的是,const_cast的目的是为赋值一个可以更改const变量的指针或引用,并不是消除某个具有const属性的const,比如上述代码,可以通过rp更改a,但是a的本身还是不能够更改。
3.4 dynamic_cast
dynamic_cast作用于继承场景下并且父类必须含虚函数(即满足多态类型),将一个指向父类对象的指针/引用转换为一个指向子类对象的指针/引用,又称为动态转换。
多态的指针或引用转换分两种情况:
1、向上强制转换,即子类指针/引用->父类指针/引用,这种情况下可以正常转换,因为可以看成是一种权限缩小的过程。
2、向下强制转换,即父类指针/引用->子类指针/引用,这种情况下就必须要用dynamic_cast进行转换了。
值得注意的是:并不是只要使用了dynamic_cast就能实现父类指针/引用->子类指针/引用,在某些场景是实现不了转换的,比如一个指向父类对象的指针,若将他转换成子类指针则会发生越界访问,具体示意图如下:

以上情况dynamic_cast是不会发生转换的,他会返回0表示转换失败。
只有当父类指针指向的空间是一块子类类型的空间,此时想把该父类型指针转换为子类型指针则可以成功,如下图所示:

dynamic_cast测试代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class A
{
public:
virtual void f() {}
};
class B : public A
{
public:
int a;
};
void fun(A* pa)
{
// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
B* pb1 = static_cast<B*>(pa);//不安全的转换
B* pb2 = dynamic_cast<B*>(pa);//安全的转换
cout << "pb1:" << pb1 << endl;
cout << "pb2:" << pb2 << endl;
}
int main()
{
A a;
B b;
fun(&a);//a的类型是父类,无法转换
fun(&b);//b的类型是子类,可以转换
return 0;
}
运行结果:

从结果可以看到,dynamic_cast相比于直接转换其实是更加安全的,只有出现越界访问的风险,dynamic_cast就直接返回0,即nullptr。
结语
以上就是关于C++强制类型转换的讲解,上文介绍了四种强制类型转换符,他们的作用不仅仅是提高可读性,还有着安全检测的作用,因此使用这四种转换符可以提高代码的规范性。最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!

5197

被折叠的 条评论
为什么被折叠?



