C++ 的强制类型转换


C++ 的强制类型转换

文章插图
作者 | 樱雨楼
责编 | 屠敏
出品 | CSDN(ID:CSDNnews)
在上篇与中篇中,我们讨论了隐式类型转换及其与函数重载之间的相关话题 。本篇将要讨论的即为类型转换的另一大分支——强制类型转换 。
1.C风格的强制类型转换
在C语言中,强制类型转换存在两种等价形式:Type(Value)或(Type)Value 。
参考以下代码:
int main{(int *) malloc(0); // (Type)Value形式的强制类型转换int(0.); // Type(Value)形式的强制类型转换}上述代码中,我们分别使用了C语言的提供的两种强制类型转换的等价形式将void *转为了int *,以及将double转为了int 。
2.static_cast
在C++中,staticcast相当于C语言中的强制类型转换语法 。staticcast用于在编译期对某种类型的变量进行强制类型转换 。
参考以下代码:
int main{static_cast<int *>(malloc(0));static_cast<int>(0.);}上述代码中,我们使用了static_cast分别将void *转为了int *,以及将double转为了int 。
3.const_cast
constcast是C++中专用于处理与const相关的强制类型转换关键字,其功能为:为一个变量重新设定其const描述 。即:constcast可以为一个变量强行增加或删除其const限定 。
需要明确的是,即使用户通过constcast强行去除了const属性,也不代表当前变量从不可变变为了可变 。constcast只是使得用户接管了编译器对于const限定的管理权,故用户必须遵守“不修改变量”的承诺 。如果违反此承诺,编译器也不会因此而引发编译时错误,但可能引发运行时错误 。
下面讨论const_cast的主要用途 。
考察以下代码:
struct A { A &test { return *this; } };int main{A.test;}这段代码看上去运行正常 。但如果:
struct A { A &test { return *this; } };int main{const A a;a.test; // Error!}我们试图用一个const对象去调用非const成员函数,此时,为了调用此成员函数,const A *this就需要转换为A *this,这显然是不行的 。
经过上述讨论,我们可以将代码修改为如下:
struct A { const A &test const { return *this; } };int main{const A a;a.test;}我们将this指针声明为const A *,解决了此问题 。但不难发现,如果我们通过一个非const对象调用此方法,其返回值也会被转为const,从而不再可以继续调用任何接受A *this的成员函数 。这明显不是我们想要的结果:
struct A{const A &test const { return *this; }A &test2 { return *this; }};int main{A.test.test2; // Error!}怎么解决此问题呢?根据C++函数重载的规则,我们可以为test成员函数同时定义const与非const版本:
struct A{A &test { return *this; }const A &test const { return *this; }A &test2 { return *this; }};int main{A.test.test2;const A a;a.test;}对于A的非const实例而言,test的非const版本是精确匹配,故编译器将选择此版本,从而返回一个A &;同时,对于A的const实例而言,const版本的test是其唯一可用的版本,返回一个const A & 。
至此,问题解决了 。我们基于const的有无重载出了两个版本的成员函数,从而使得const对象与非const对象能够各自调用不同的版本,互不影响 。
在实际情况中,我们定义的两个版本的重载函数除了有无const以外往往没有任何区别,此时就可以使用const_cast定义第二个重载版本,而无需写两遍一模一样的函数体 。
参考以下代码:
struct A{A &test { ... }// 通过const_cast强行去除this的const限定后调用非const版本// 返回值通过隐式类型转换再转回const A &const A &test const { return const_cast<A *>(this)->test; }};上述代码中,我们首先定义了一个非const版本的test成员函数,这个成员函数将提供给A *this调用;在定义test成员函数的const版本时,我们通过const_cast<A *>(this),将此版本的const A *this指针转换为非const版本需要的A *this类型指针,然后调用了非const版本的test成员函数,并返回其调用结果,非const版本的test成员函数的返回值将通过隐式类型转换转为const A & 。
由此可见,通过const_cast,我们仅需一行代码就可以完成第二个函数重载版本的定义 。
4.dynamic_cast
上文提到,动态类型为继承类的指针或引用可以存储在静态类型为基类的变量中,且不会发生隐式类型转换 。对于一个变量而言,虽然其动态类型确实是继承类,但由于编译期与运行期的差别,其也无法跨越“可使用的成员名称由静态类型决定”这一规则 。


推荐阅读