1.static_cast
C语言中所有的隐式类型转换,都可以使用static_cast进行来完成。
int a = 10;
char ch = static_cast<char>(a);
2.reinterpret_cast
reinterpret_cast可以对变量进行重新解释,像一个指针的编号可以解释为一个整型。
int a = 10;
int* pa = &a;
a = reinterpret_cast<int>(pa);
cout << "reinterpret_cast: " << a << endl;
此时cout打印的是一个内存编号(整型):
3.const_cast
const定义的常变量是不能进行重新赋值的,但是如果我们使用const_cast让一个指针指向一个const变量所在的空间,就可以通过指针来修改;对应的是C语言的强制类型转换。
const int a = 10;
int* pa = const_cast<int*>(&a);
*pa = 20;
cout << a << endl; //10
cout << *pa << endl;//20
pa中存储的是a的地址,*pa和a打印出来的值理论上来说是一样的,那为什么打印的值不一样?
解答:const修饰的常变量,编译器会做出一些优化,如直接放在寄存器中,或者是定义成一个宏;在流插入时a不会去内存中去取,而是直接找到寄存器或者宏,所以打印的还是10;而*pa会去内存中找,所以打印的是20。
4.dynamic_cast
父类指针或引用可以指向子类的指针或引用,但是如果直接使用子类指针或引用指向父类的指针或引用就会报错。
注意:父类对象是无论如何都无法转换成子类对象的。
class A
{
public:
virtual void f() {}
};
class B : public A
{};
int main()
{
A aa;
B bb;
bb = aa;
bb = (B)aa;
bb = dynamic_cast<B>(aa);
return 0;
}
这三种写法都是错误的:
dynamic_cast的使用时是条件的:继承关系,父类必须有虚函数,向下转型。
class A
{
public:
virtual void f(){}
public:
int _a = 0;
};
class B : public A
{
public:
int _b = 1;
};
// A*指针pa有可能指向父类,有可能指向子类
void fun(A* pa)
{
// 如果pa是指向子类,那么可以转换,转换表达式返回正确的地址
// 如果pa是指向父类,那么不能转换,转换表达式返回nullptr
B* pb = dynamic_cast<B*>(pa); // 安全的
//B* pb = (B*)pa; // 不安全
if (pb)
{
cout << "转换成功" << endl;
pb->_a++;
pb->_b++;
cout << pb->_a << ":" << pb->_b << endl;
}
else
{
cout << "转换失败" << endl;
pa->_a++;
cout << pa->_a << endl;
}
}
int main()
{
A aa;
B bb;
fun(&aa);
fun(&bb);
return 0;
}
使用强制类型转换和dynamic_cast进行转换的区别:
强制类型转换不会做表达式返回检查,类型能够转换成功,但是访问时可能访问到非法地址,如给fun函数传递的是父类的指针,强制将父类指针转化为子类去访问成员变量_b就是非法访问;使用dynamic_cast进行父类转子类时,会进行类型检查,如果是父类指针,会返回nullptr,如果是子类指针,就可以进行转换。