C++类型转换
我们先来看一看以前是怎么定义数据类型转换的:
#include <iostream>
using namespace std;
void Test()
{
//隐式的类型转换
int i = 10;
double d = i;
printf("%d ,%.2f\n", i, d);
//显式的强制类型转换
int* p = &i;
int address = (int)p;
printf("%x ,%d\n", p, address);
}
int main()
{
Test();
return 0;
}
这种转换有一个缺陷就是:强制转换可视效果差,所有的转换形式都是同一种形式书写,如果出现错误,不容易跟踪错误的转换。
C++类型转换
为了解决强制转换带来的可视化效果差的问题引入了四种命名的强制类型转换操作符:static_cast,reinterpret_cast,const_cast,dynamic_cast
四个操作符你见过几个?哈哈哈,没见过也没关系,我也没见过几个。下面我仔细地解释这四个操作符:
• static_cast
static_cast用于非多态类型的转换(也叫静态转换),编译器隐式执行的任何类型转换都可以用static_cast,但它不能用于两个不相关的类型进行转换,干说条条没有用,我们看一看它是怎么使用的吧:
int main()
{
double d = 13.14;
int i = static_cast<int>(d);
cout << i << endl;
return 0;
}
怎么理解不能用于两个不相关的类型进行交换呢?
double和int都是同一类型,但是a是一个int类型的变量,而我们却把的强转成(int*)类型当然是不可以了,一个是整形,一个是指针类型,这就叫不相关类型
•reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于一种类型转换为另一种不同的类型。它不允许删除const,但会执行一些令人生厌的操作,程序猿还不得不去依赖的操作,通过,这样的类型转换适用于依赖于实现底层编程技术。
typedef void (*FUNC)(); //定义一个函数指针
int DoSomething()
{
cout << "DoSomething" << endl;
return 0;
}
void Test()
{
FUNC f = reinterpret_cast<FUNC> (DoSomething());
//f(); //错误,不能将函数指针转换为数据指针
}
int main()
{
Test();
return 0;
}
reinterpret_cast可以让编译器一FUNC的定义方式去看待DoSomething函数,但是C++不能保证所有的函数指针都被一样的使用,所以这使用有时会产生不确定的结果
•const_cast
const_cast最常用的就是删除变量的const属性,方便赋值
int main()
{
const int i = 10;
int *p = const_cast<int *>(&i);
*p = 20;
cout << i << endl;
return 0;
}
为什么要用指针而不是其他类型呢?
我们看看不用指针会出现什么结果:
注意:const_cast不是万能的,他可以修改一个值的指向,但修改const值的结果是不确定的,看个例子:
void Change(const int* pt, int n)
{
int* pc;
pc = const_cast<int*>(pt);
*pc += n;
}
int main()
{
int p1 = 1234;
const int p2 = 5678;
cout << "p1,p2" << p1 << " " << p2 << endl;
Change(&p1, -4);
Change(&p2, -4);
cout << "p1,p2" << p1 << " " << p2 << endl;
return 0;
}
p1和p2都改变了吗?
const_cast可以删除const int * pt的const属性,使得编译器能够接受Change()中的语句。但由于p2被声明为const,因此编译器可能会禁止修改它。所以说,修改const值的结果是不确定的,但仅当指向的值不是const时才可行。
•dynamic_cast
dynamic_cast用于将一个父类对象的指针转换为子类对象的指针或者引用(动态转换)
动态转换又分为:
向上转型:子类对象指针->父类对象指针/引用(不需要转换,遵循赋值兼容规则)
向下转型:父类对象指针->子类对象指针/引用(用dynamic_cast转型是安全的)
使用这个操作符时注意事项:
1、dynamic_cast只能用于检查含有虚函数的类
2、dynamic_cast会先检查能否转换成功,能成功则转换,不能成功则返回0
class A
{
public:
virtual void f()
{}
};
class B :public A
{};
void fun(A* pa)
{
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << "pb1:" << pb1 << endl;
cout << "pb2:" << pb2 << endl;
}
int main()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}