cpp四种cast

四种转换介绍

C风格转换:转换的含义是通过改变一个变量的类型为别的类型从而改变该变量的表示方式。为了类型转换一个简单对象为另一个对象,会使用传统的类型转换操作符。比如,为了转换一个类型为 double 的浮点数的指针到整型:

1
2
3
4
int i;
double d;
i = (int)d;
i = int(d);

对于具有标准定义转换的简单类型而言很好。但是这样的转换符不能随意用于类(class)和类的指针。标准定义了四个新的转换符:reinterpret_cast, static_cast, dynamic_cast 和 const_cast,目的在于控制类之间的类型转换。

reinterpret_cast

reinterpret_cast 转换一个指针为其它类型的指针。它也允许从一个指针转换为整数类型。反之亦然。这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。

代码:

1
2
3
4
class A {};
class B {};
A *a = new A;
B *b = reinterpret_cast<B *>(a);

reinterpret_cast 就像传统的类型转换一样对待所有指针的类型转换。

static_cast

static_cast 允许执行任意的隐式转换和相反转换动作。(相关类之间转换)

应用到类的指针上,意思是说它允许子类类型的指针转换为父类类型的指针(这是一个有效的隐式转换),同时,也能够执行相反动作:转换父类为它的子类。

在这最后例子里,被转换的父类没有被检查是否与目的类型相一致。

代码:

1
2
3
4
class Base {};
class Derived : public Base {};
Base *a = new Base;
Derived *b = static_cast<Derived *>(a);

static_cast 除了操作类型指针,也能用于执行类型定义的显式的转换,以及基础类型之间的标准转换:

1
2
double d = 3.14159265;
int i = static_cast<int>(d);

如果转换的类型之间没有关系的话,会报编译错误:

1
2
3
4
5
@└────> # g++ test.cc 
test.cc: In function ‘int main()’:
test.cc:12:41: error: invalid static_cast from type ‘Base*’ to type ‘Derived*’
Derived *b = static_cast<Derived *>(a);
^

如果子类中有基类没有的对象,那么转换后使用则不安全。

dynamic_cast

dynamic_cast 只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与 static_cast 不同,在自上而下的转换过程中, dynamic_cast 会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
代码:

1
2
3
4
5
6
7
8
class Base { virtual dummy() {} };
class Derived : public Base {};

Base* b1 = new Derived;
Base* b2 = new Base;

Derived* d1 = dynamic_cast<Derived *>(b1); // 成功
Derived* d2 = dynamic_cast<Derived *>(b2); // 失败,返回NULL

用于安全向下转型,成本非常高昂。

const_cast

这个转换类型操纵传递对象的 const 属性,或者是设置或者是移除
代码:

1
2
3
class C {};
const C *a = new C;
C *b = const_cast<C *>(a);

其它三种操作符是不能修改一个对象的常量性的。
const_cast 在调用第三方函数中的使用:
在使用第三方库或API时,它们只提供了非 const 类型的参数的函数,但我们只有 const 类型的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
int third_lib_fun(int *ptr) {
*ptr = *ptr + 10;
return (*ptr);
}
int main(void) {
int val = 10;
const int *ptr = &val;
int *ptr1 = const_cast<int *>(ptr);
third_lib_fun(ptr1);
cout << val;
return 0;
}

输出结果:

1
20

我们在使用第三方库和 API 的时候,我们只能调用,看不到其具体的实现,为了能够调用成功,需要使用 const_cast 来去除 *ptr 的 const 属性。