隐式类型转化:相关类型的转换,即意义相似的类型。
强制类型转化:不相关类型的转换,比如:指针和整型.
static_cast
用法:static_cast<类型说明符> (变量或表达式)
作用:显式、静态地执行隐式类型转换和用户定义的转换,不进行运行时检查。
分类:
- 用于基本类型数据的转换
float a = 2.3;
int b = static_cast<int>(a);
- 把空指针转换成目标类型的空指针
- 把任何类型的表达式转换为void类型
- 父类指针/引用到子类指针/引用的转换,是不安全的
class A
{
public:
A() {}
};
class B : public A
{
public:
B() {}
};
void test()
{
//父类指针到子类指针的转换,不安全
A* a = new A;
B* b = static_cast<B*> (a);
}
注意:static_cast只能在有相互联系的类型中进行相互转换,不相关类型是不可以转换的。
int a = 10;
int *b = static_cast<int*>(a); //a为整形,转为int*是不可以的
整形和指针属于两种完全不同的类型,所以是不可以通过static_cast转换。
reinterpret_cast
作用:不相关类型的转换(相当于C语言中的强转)
int a = 10;
int *b = reinterpret_cast<int*>(a);
const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值
const int a = 10;
int *p = const_cast<int*>(&a);
但是,const_cast是不能用来执行任何类型的转换的,这样都会引起编译错误的!
const char t = 'a';
int *p = const_cast<int*>(&t); //编译错误
const_cast只能调节类型限定符,不能更改基础类型。
下面我们来看一段代码:
const int a = 10;
int *p = const_cast<int*>(&a);
*p = 20;
cout << "a: " << a << endl;
cout << "*p: " << *p << endl;
我们预期的结果,a为20,*p也为20。打印结果:
在内存中,a已经改为20,但是打印确实10。其实是编译器在这里玩了个小聪明,
const int a=10
,编译器认为a就不会发生改变了,所以就把a放在了寄存器中,因为访问寄存器要比访问内存单元快的多,每次都从寄存器中取数据,但是后来a在内存中发生变化后,寄存器中的数据没有发生变化,所以打印的是寄存器中的数据。
可以通过volatile关键字这个问题。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。避免过度优化。
volatile const int a = 10;
int *p = const_cast<int*>(&a);
*p = 20;
cout << "a: " << a << endl;
cout << "*p: " << *p << endl;
在写代码的过程中要注意这个问题。
dynamic_cast
多态场景下用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用- >子类指针/引用(用dynamic_cast转型是安全的)
注意:
- dynamic_cast只能用于含有虚函数的类
- dynamic_cast在运行期强制转换,运行时进行类型检查,若安全,才会转化成功。
- 对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针。
- 对引用进行dynamic_cast,失败抛出一个异常bad_cast,成功返回正常cast后的对象引用。
- 不能用于内置的基本数据类型的强制转换。
class A
{
public:
virtual void fun() {}
};
class B : public A
{
};
void test()
{
A* pb = new A;
B* pb2 = static_cast<B*> (pb);
B* pb3 = dynamic_cast<B*>(pb);
cout << pb2 << endl;
cout << pb3 << endl;
pb = new B;
pb2 = static_cast<B*> (pb);
pb3 = dynamic_cast<B*>(pb);
cout << pb2 << endl;
cout << pb3 << endl;
}
总结:
- 去const属性用const_cast
- 基本类型转换用static_cast
- 多态类之间的类型转换用daynamic_cast
- 不同类型的指针类型转换用reinterpreter_cast