c语言强制类型转换 谁说 C+的强制类型转换很难懂

栏目:科技 2021-09-20 00:33:04
分享到:

作者|樱雨屋

编辑|涂敏

由| CSDN制作

c风格强制类型转换

在C语言中,强制类型转换有两种等价形式:类型或值。

参见以下代码:

在上面的代码中,我们使用了C语言提供的两种强制类型转换的等价形式,将void *转换为int *并将double转换为int。

静态转换

在C++中,staticcast相当于C语言中的强制类型转换语法。Staticcast用于在编译时强制转换一种类型的变量。

参见以下代码:

在上面的代码中,我们使用static_cast将void *转换为int *并将double转换为int。

const_cast

Constcast是C++中专门用来处理与const相关的强制类型转换的关键字。它的功能是重置变量的常量描述。也就是说,constcast可以强制添加或删除变量的const限制。

应该明确的是,即使用户通过constcast强制移除const属性,也并不意味着当前变量已经从不可变变为可变。Constcast只是让用户接管编译器对const的管理权,所以用户必须遵守“不修改变量”的承诺。如果违反了这一承诺,编译器将不会导致编译时错误,但可能会导致运行时错误。

const_cast的主要用途将在下面讨论。

检查以下代码:

这段代码似乎运行正常。但是如果:

我们尝试使用一个const对象来调用一个非const成员函数。此时,为了调用这个成员函数,需要将const A *this转换为A *this,这显然是不可行的。

经过以上讨论,我们可以修改代码如下:

我们通过声明这个指针常量A *来解决这个问题。但是不难发现,如果我们通过一个非const对象调用这个方法,它的返回值也会被转换为const,所以我们不能再继续调用任何接受A *this的成员函数。这显然不是我们想要的结果:

如何解决这个问题?根据C++函数重载的规则,我们可以同时为测试成员函数定义常量和非常量版本:

对于A的非常数实例,test的非常数版本是完全匹配的,所以编译器会选择这个版本,从而返回A & amp;;同时,对于的const实例,test的const版本是唯一可用的版本,它返回一个const A & A。

至此,问题已经解决。我们已经根据const的存在与否重载了两个版本的成员函数,这样const对象和non-const对象可以调用不同的版本而不会相互影响。

实际上,除了是否有常量之外,我们定义的重载函数的两个版本没有区别。此时,我们可以使用const_cast来定义第二个重载版本,而无需编写两次相同的函数体。

参见以下代码:

在上面的代码中,我们首先定义了一个非常数版本的测试成员函数,它将为a*这个调用提供;在定义测试成员函数的const版本时,我们使用const_cast将这个版本的const a*这个指针转换成非const版本所需要的a*这个类型指针,然后调用测试成员函数的非const版本并返回其调用结果。测试成员函数的非常量版本的返回值将通过隐式类型转换转换为常量A & A。

因此,通过const_cast,我们只需要一行代码来定义第二个函数的重载版本。

动态强制转换

如上所述,动态类型为继承类的指针或引用可以存储在静态类型为基类的变量中,不会发生隐式类型转换。对于一个变量,虽然它的动态类型确实是一个继承类,但是由于编译时和运行时的不同,它不能违反可用成员名称由静态类型决定的规则。

虽然继承类可以通过虚函数的方式在一定程度上解决这种情况,但是如果成员函数只存在于继承类中而不是基类的虚函数中呢?Dynamic_cast为我们提供了一个解决方案。

当静态类型为基类指针或引用的变量确实存储了继承的类指针或引用时,从基类到继承类的类型转换,即向下类型转换,理论上是可行的,在运行时使用dynamic_cast实现向下类型转换。

需要注意的是,dynamic_cast的使用必须同时满足以下所有条件:

转换后的变量的类型是基类指针或引用,并且它确实持有继承的类指针或引用

基类有一个虚拟表,也就是说,基类必须定义至少一个虚拟函数

参见以下代码:

在上面的代码中,我们首先用虚函数定义基类A,然后用继承的类特定函数定义类B。此时,由于test2成员函数没有在基类中注册为虚函数,我们将无法通过静态类型为A *的变量b调用该函数。但是,由于我们可以确定变量B的动态类型是B *,所以我们可以在运行时通过dynamic_cast将变量B的静态类型更改为B *,然后调用继承类的特殊函数test2。

重新解释_cast

重新解释,也就是“重新解释”,顾名思义,这种强制类型转换的作用是为变量提供对底层数据的重新解释。当我们对一个变量使用重新解释时,编译器将忽略任何不合理的行为,并强制将转换后的变量的内存数据重新解释为新的类型。需要注意的是,重新解释cast要求转换前后类型占用的内存大小一致,否则会抛出编译时错误。

参见以下代码:

讨论

多年来,编程语言中的强类型和弱类型的话题在业界一直被无休止地讨论。一些语言开发了高度弱类型的语法系统,而另一些语言则相对严格,要求用户尽可能使用显式类型转换。C++作为一种经典的弱类型语言,有一个巨大的类型转换话题。

纵观C++中类型转换的语法体系,它延续了C++包罗万象的风格,不仅为用户提供了极大的自定义类型转换的自由,还对类型转换可能带来的各种复杂情况做出了严格的规定。

保守地说,如果我们对C++类型转换没有很深的理解,或者不想大量使用隐式类型转换,就不应该过度依赖非显式转换构造函数、用户定义的类型转换运算符以及涉及隐式类型转换的各种重载判定等语法组件。然而,作为C++语法体系的重要组成部分,深刻理解C++中关于类型转换的各种主题是非常重要的。

关于作者:颖娄宇,生物信息学毕业,用Python/C++/Perl开发,自称R语言黑粉,和GitHub勾搭:https://github.com/yingyulou

热门文章推荐