C++类型转换

C++中常用的类型转换方式有reinterpret_cast、static_cast、dynamic_cast,下面介绍他们的作用和使用场景。


1、reinterpret_cast

1.1、含义

reinterpret翻译过来是“重新解释”,字面上的意思就是将对象重新解释为另一个类,也就是强制转换,实际上它的作用也是如此。

1.2、示例

例:
现有A类和B类。

#include <iostream>

using namespace std;

class A
{
public:
    int data { 100 };
};

class B 
{
public:
    char data[4] { 0 };
};

我们用reinterpret_cast来转换,为了演示效果更好,准备一个数字6666,它的十六进制是1A0A。

int main()
{
    B *b = new B;
    A *a = reinterpret_cast<A*>(b);
    cout << a->data << endl;
    b->data[0] = 0x0A;
    b->data[1] = 0x1A;
    cout << a->data << endl;

在这里插入图片描述
可以看到,reinterpret_cast是直接将b对象的那块内存当作A类型来解释了。

1.3、存在的问题

上一节说到reinterpret_cast是将一个对象的内存当作另一个类型来解释,那么在C++中就会存在一些风险,常见风险如下:

  1. 访问指针时可能会导致程序崩溃。以上述的例子来说,如果A类中的data是一个指针,而b对象的data存放的并不是指针,那么就可能出现访问野指针的情况。
  2. 调用虚函数时可能导致程序崩溃。我们知道,C++的虚函数也是通过函数指针来实现的,如果A和B的虚函数数量不一致,那在调用虚函数时,也有可能会访问到野指针。
  3. 数据错乱。这一点在上一节的例子中也有所体现了。

1.4、应用场景

reinterpret_cast一般用在待强转的对象是确定的且可被强转的情况,比如上面的例子,我们清楚B的储存结构是安全的,而且b来自于new B,而不是经过其它函数传参过来的。
具体应用有:同一父类下的子类互转,结构体互转。

2、static_cast

2.1、作用

static_cast也是一种类型转换的方式,它与reinterpret_cast的不同之处在于,它在编译的时候会查错,也就是如果类型转换有问题,我们写代码的时候会提示。
例如:
在这里插入图片描述

2.2、存在的问题

虽然static_cast会查错,但也还是存在着风险,比如以下例子:
在这里插入图片描述
类型B有虚函数表,而A没有,显然这个程序运行会崩溃,但static_cast并没有报错,这是因为static_cast转换时只会检查它们时候有继承关系,如果有,那就认为是合法的。

static_cast查错的逻辑可以参考下图,我们创建了一个Grand类型对象来转换为其它类型,绿线为合法,红线为非法。
在这里插入图片描述

2.3、应用场景

从上一节可以看到,static_cast适用于一些继承关系比较简单的场景,如果继承关系比较简单,用static是比较安全的。

3、dynamic_cast

3.1、作用

dynamic_cast是static_cast的进阶版,它不仅在编译时会查错,在程序运行时也会查错。
它在编译时查错和static_cast有一些区别,需要分两种情况来介绍。

  1. 对象无虚函数表。此时dynamic_cast会比较严格地检查继承关系是否合法,如下图所示,弥补了static_cast的不足。
    在这里插入图片描述
  2. 对象有虚函数表。此时编译器不会查错。
    在这里插入图片描述

我们可以看到,如果对象有虚函数表,dynamic_cast的查错就会在编译阶段失效,这时候就需要用到它的运行时查错。
当转换不合法时,dynamic_cast会返回NULL,还是刚刚的例子。
在这里插入图片描述
在这里插入图片描述
这两种不合法的转换返回了NULL。

dynamic_cast运行时查错的逻辑可以参考下图,绿线表示正常转换,红线表示返回NULL。
在这里插入图片描述

3.2、存在的问题

dynamic_cast因为在运行时会查错,所以效率比前两者慢,不过性能损耗不大,这个可以视具体需求而定。

3.3、应用场景

dynamic_cast是一种安全度比较高的转换方式,可以适应于大部分情况,我们使用的时候可以用这种格式,要注意异常情况的处理。

A *a = new A;
B *b = dynamic_cast<B*>(a);
if (b != NULL) {
	// dosomething
} else {
	// exception handle
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值