C++中的强制类型转换主要有4种static_cast、dynamic_cast、const_cast、reinterpret_cast
1.static_cast
静态类型转换,使用形式如下:
static_cast<new_type> (expresion);
其中new_type为目标类型,expresion为原始数据类型变量或表达式。
static_cast用来强迫隐式转换,如将non-const对象转为const对象,编译时进行检查,但没有运行时类型检查来保证转换的安全性。主要有以下几种用法:
- 用于类层次结构中基类和派生类之间指针或引用的转换。此时,进行上行转换(即把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,是不安全的。
- 用于基本数据类型之间的转换,如把int转换为char,int转换为enum,这种转换的安全性需要开发人员来保证。
- 把空指针转换成目标类型的指针(这是极其不安全的)
- 把任何类型的表达式转换成void类型
- static_cast无法转换掉expression的const,volatile,__unaligned属性
示例如下:
char a = 'a';
int b = static_cast<int>(a);//正确,将char型数据转换成int型数据double *c = new double;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针int e = 10;
const int f = static_cast<const int>(e);//正确,将int型数据转换成const int型数据const int g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性
2.dynamic_cast
动态类型转换,形式如下:
dynamic_cast<type>(expression);
dynamic_cast会在运行时检查类型转换是否合法,在进行上行转换时,dynamic_cast和static_cast没有区别,都是安全的;下行转换时,dynamic_cast会检查转换的类型,比static_cast安全。
- 不能用于内置的基本数据类型的强制转换
- dynamic_cast转换如果成功返回的是指向类型的指针或引用。转换目标类型是指针且失败,则返回NULL;如果转换模板类型是引用且失败,则抛出std::bad_cast异常
- 转换类指针时,基类中一定要有虚函数
为什么基类中一定要有虚函数?dynamic_cast转换是在运行时进行转换,运行时转换就需要知道类对象的信息(继承关系等)。虚函数表可以帮助在运行时获取这些信息。在C++对象模型中,对象实例最前面的就是虚函数表指针,通过这个指针可以获取到该类对象的所有虚函数,包括父类的,因为派生类会继承基类的虚函数表,在转换时可以用来判断对象有无继承关系。
示例1:继承中的转换
上行转换中,dyanmic_cast与static_cast一样,是安全的。在下行转换时
class A { virtual void f(){}; };
class B : public A{ };
void main()
{A* pA = new B;B* pB = dynamic_cast<B*>(pA);
}
类A中必须要有虚函数,因为dynamic_cast运行时类型检查需要运行时类型信息,这些信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表
示例2:void*转换
有些时候,需要将指针转换为void*,然后在合适的时候重新将void*转换为目标类型指针
class A { virtual void f(){} };
int main()
{A *pA = new A;void *pV = dynamic_cast<void *>(pA);
}
示例3:菱形继承中的上行转换
class A { virtual void f() {}; };
class B :public A { void f() {}; };
class C :public A { void f() {}; };
class D :public B, public C { void f() {}; };
继承关系为:
此时:D对象指针能否安全的转换为A类型的指针?
void main()
{D *pD = new D;A *pA = dynamic_cast<A *>(pD); // pA = NULL
}
结果得到一个空指针。这是因为B和C都实现了虚函数,导致在进行转换时,无法选择一条转换路径。一种方法是:指定一条转换路径
void main()
{D *pD = new D;B *pB = dynamic_cast<B *>(pD);A *pA = dynamic_cast<A *>(pB);
}
3.const_cast
主要用来去掉类型的const、volatile和__unligned属性。形式为:
const_cast<type>(expression);
常量指针被转换成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然引用原来的对象。
const char *pc;
char *p = const_cast<char*>(pc);
4.reinterpret_cast
非常激进的类型转换,形式为:
reinterpret<type>(expression);
type必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。
dynamic_cast是在运行时检查,其他3种都是在编译时完成。