我们知道,相对于C语言中粗暴的直接类型转换,C++中为每种必要的类型转换提供了分别不同的类型转换运算符关键字。在C中各种类型转换的运算符是一样的,这样的话,导致的后果是:当发生类型转换相关的bug时,我们不知到如何去查找,因为各种类型转换的运算符是一样的。但是在C++中,我们可以很容易地找到,因为在C++中各种类型转换的运算符关键字是不同的。
在C++中对于不同目的的类型转换提供不同的运算符,总结如下:
reinterpret_cast
只能用于指针的转换,将一个类型的指针转换为另一个类型的指针.或者将一个指针数值直接转换成整数。这种转换不会修改指针变量值存放格式(不改变指针变量值), 只需在编译时重新解释指针的类型就可做到.
- #include <cstdio>
-
#include <iostream>
-
#include <iomanip>
-
-
using std::endl;
-
using std::cout;
-
using std::dec;
-
using std::hex;
-
-
int main()
-
{
-
double pi = 3.1415926;
-
int *ppi = reinterpret_cast<int *>(&pi);
-
cout << pi << endl << *ppi << endl << endl;
-
-
class A{};
-
class B{};
-
A *pa = new A;
-
B *pb = reinterpret_cast<B*>(pa);
-
-
printf("pa: %p\npb: %p\n\n", pa, pb);
-
int i = 100;
-
int j = (int)&i;
-
-
printf("%p\n0x%x\n\n", &i, j);
-
-
cout << "reinterpret_cast(int*):" << endl;
-
int m = reinterpret_cast<int>(&i);
-
cout << "0x" << hex << m << endl << &i << endl << endl;
-
-
cout << "reinterpret_cast(int):" << endl;
-
int* pint = reinterpret_cast<int*>(100);
-
cout << "0x" << 100 << endl << pint << endl << endl;
-
-
return 0;
-
}
运行结果为:
- 3.14159
-
1293080650
-
-
pa: 0x902b008
-
pb: 0x902b008
-
-
0xbff92004
-
0xbff92004
-
-
reinterpret_cast<int>(int*):
-
0xbff92004
-
0xbff92004
-
-
reinterpret_cast<int*>(int):
-
0x64
-
0x64
可以看到C++中的reinterpret_cast(int* )等价于C中的 int i = (int)(int* )
reinterpret_cast(int )等价于C中的 int* pi = (int*)(int )
注: reinterpret_cast字面的意思是“重新解释的转换”,它只是对指针进行重新的解释,所以它不会修改该指针的值。关于reinterpret_cast只要记住两点:
(1)它能将任何指针转换成任何指针,它能将指针转换成整数,也能将整数转换成指针。
(2)它不会改变被转换的指针。它不能用对象之间的转换。
关于这两点其实很好理解:指针无非就是一个4字节或者8字节的数字而已,只不过这个数字是某个变量或对象的地址。对这个地址进行reinterpret_cast,就是对该地址所指向的变量或对象进行“重新解释”。
而“指针与整数之间的转换”是因为它们大小相同都是4字节或者8字节。
const_cast
该函数用于去除指针变量的常量属性,将它转换为一个对应指针类型的普通变量。反过来,也可以将一个非常量的指针变量转换为一个常指针变量。
这种转换是在编译期间做出的类型更改。
例:
- #include <iostream>
-
using std::cout;
-
using std::endl;
-
-
int main()
-
{
-
const int i = 1;
-
const int *pci = &i;
- // *pci = 10; // error: assignment of read-only location ‘* pci’
-
cout << *pci << endl;
-
-
int *pk = const_cast<int*>(pci); //相当于 int *pk = (int *)pci
-
*pk = 100;
-
cout << *pci << endl;
-
return 0;
-
}
-
const A* pca = new A;
-
A* pa = const_cast<A*>(pca); //相当于A* pa = (A*)pca;
出于安全性考虑,const_cast无法将非指针的常量转换为普通变量。
static_cast
该函数主要用于基本类型之间和具有继承关系的类型的对象或者变量之间的转换。
这种转换一般会更改变量的内部表示方式,因此,static_cast应用于指针类型转换没有太大意义。
例:
- int i=0;
-
double d = static_cast<double>(i);
-
class Base{};
-
class Derived : public Base{};
-
Derived d;
-
Base b = static_cast<Base>(d);
注:动态只有static_cast能用于变量或对象的转换,而不是它们的指针的转换。虽然是基本类型的变量和继承关系的对象。
dynamic_cast
它与static_cast相对,是动态转换。这种转换是在运行时进行转换分析的,并非在编译时进行,明显区别于上面三个类型转换操作。所以它对程序的性能是有所影响的!
该函数只能在继承类对象的指针之间或引用之间进行类型转换。进行转换时,会根据当前运行时类型信息,判断类型对象之间的转换是否合法。dynamic_cast的指针转换失败,可通过是否为null检测,引用转换失败则抛出一个bad_cast异常。
- class Base{};
-
class Derived : public Base{};
-
Derived *pd = new Derived;
-
Base *pb = dynamic_cast<Base*>(pd);
-
if (!pb)
- cout << "dynamic_cast failed." << endl;
-
class A(virtual ~A();) //有虚函数
-
class B{}:
-
A* pa = new A;
-
B* pb = dynamic_cast<B*>(pa);
- if(pb)
- cout << "dynamic_cast succeeded." << endl;
如果对无继承关系或者没有虚函数的类的对象指针进行转换、基本类型指针转换以及基类指针转换为派生类指针,都不能通过编译。
我们看到:
(1)各种类型的转换各司其职,有继承关系的对象或变量之间的转换用static_cast,而指针之间或者指针和整数之间的转换用reinterpret_cast,动态指针的转换用dynamic_cast。
(2)我们可以在基本类型的变量和继承关系的对象之间进行转换,我们可以将指针转换成整数,我们可以将任何类型的指针转换成任何类型的指针,我们可以去掉或加上const属性在指针上。
(3)利用C++中的reinterpret_cast、static_cast、dynamic_cast、const_cast等关键字,可以完全抛弃C中的强制转换。
阅读(964) | 评论(0) | 转发(0) |