在C语言中,强制类型的转换方式很简单,通过Type a = (Type)b
即可,但是这样有两个比较明显的缺点:一是转换方式过于随意,可以在指针和整数之间进行转换,这是比较危险的操作;二是这样的转换方式在多括号的情况下不够清晰和直接,进而C++推出了自己的转换方式来改善这两种情况。C++显式类型转换有四种const_cast、static_cast、dynamic_cast、reinterpreter_cast,四种转换方式各有用途,需要针对不同情况选取不同的转换方式。
static_cast
static_cast是一种最常用的转型方式,我们可以在日常转型操作中首先尝试使用它,可能在很多场景中不需要它也能够隐式的完成转型操作,但是我们还是尽可能的将转型操作显式的表现出来。
可以完成以下类型的转换
- 基本类型的转换(char转int,int转float之类)
- void类型空指针转其他类型空指针
- 任意类型转void类型指针
- 父类到子类的转换(不保证正确)
- 子类到父类的转换(保证正确)
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性
const_cast
用于将const变量转换为非const变量,这是其他任何转换类型所没有的功能。需要注意两个点
- 去除const属性不是对于最初的const对象来说,修改最初的const对象仍旧是未定义的,去除const属性是指从引用或指针的方式来去除const属性。
- const_cast只适用于指针或者引用方式
#include <iostream>
using namespace std;
class A
{
public:
void print() { cout << "hello" << endl; }
void print() const { cout << "world" << endl; }
};
int main(){
const int a=100;
cout << &a << " : " << a << endl;
int &b = const_cast<int&>(a);
b = 110;
cout << &b << " : " << b << endl;
int *pa = const_cast<int*>(&a);
*pa = 120;
cout << pa << " : " << *pa << endl;
cout << &a << " : " << a << endl;
cout << &b << " : " << b << endl;
A a;
a.print();
const A b;
b.print();
A& ref = const_cast<A&>(b);
A* ptr = const_cast<A*>(&b);
ref.print();
ptr->print();
}
输出:
0x7ffcd8468304 : 100
0x7ffcd8468304 : 110
0x7ffcd8468304 : 120
0x7ffcd8468304 : 100
0x7ffffe03f164 : 120
hello
world
hello
hello
这里明明地址一样,为什么a和b,*pa的值会不一样呢?
答:a其实用const修饰后是一个常量,在预编译阶段,常量会被真实数值替换,所以并不是cout << a << endl;而是cout << 100 << endl;
dynamic_cast
dynamic_cast转换主要用于多态方面的转换,例如父类与子类之间的互相转换。在转换过程中如果能够成功转换就返回目标类型的指针,如果不行的话就返回空指针(用指针方式转换)或者抛出异常(用引用方式转换)。在进行upcast时,static_cast和dynamic_cast具有相同的效果;但在downcast(向下转换,也就是父类向子类转换)时,dynamic_cast相对于static_cast有一个类型检查,相对来说更加安全。另外需要注意的是:
- 如果子类不是通过public继承父类的话,那么转换会失败。这是因为父类的public成员因为private继承变成了private属性(对于子类而言),子类的指针无法访问父类中的非private成员,就会出现转换失败的问题
class A {
private:
int a;
public:
A(int a_) :a(a_) {}
virtual void vprintfself(void) {
std::cout <<"a"<<this->a<<std::endl;
}
};
class B: public A {
private:
int b;
public:
B(int a_,int b_) :A(a_) { b = b_; }
void vprintfself(void) {
std::cout <<"b "<<this->b<< std::endl;
}
};
int main()
{
A* a = new A(2);
B* static_p_a_B = static_cast<B*>(a);
B* dymatic_p_a_B =dynamic_cast<B*>(a);//空指针
static_p_a_B->vprintfself();
dymatic_p_a_B->vprintfself();//报错
}
reinterpret_cast
interpret是解释的意思,reinterpret即为重新解释。这个转换几乎没什么条件限制,可以将任何指针类型转化为其他指针类型,少用为佳。
参考: