1. C++ 的强制类型转换
1)static_cast<T*>(a)
将地址a转换成类型T,T和a必须是指针、引用、算术类型或枚举类型。
① 基类和子类之间转换:其中子类指针转换成父类指针是安全的;但父类指针转换成子类指针是不安全的。(基类和子类之间的动态类型转换建议用dynamic_cast)
② 基本数据类型转换。enum, struct, int, char, float等。static_cast不能进行无关类型(如非基类和子类)指针之间的转换。
③ 把空指针转换成目标类型的空指针。
④ 把任何类型的表达式转换成void类型。
⑤ static_cast不能去掉类型的const、volitale属性(用const_cast)。
class B { ... }; class D : public B { ... }; void f(B* pb, D* pd) { D* pd2 = static_cast<D*>(pb); // 不安全, pb可能只是B的指针 B* pb2 = static_cast<B*>(pd); // 安全的 ... }
2)dynamic_cast<T*>(a)
dynamic_cast < type-id > ( expression )
如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
classB { public: int m_iNum; virtual void foo(); }; classD:publicB { public: char *m_szName[100]; }; voidfunc(B*pb) { D*pd1 = static_cast<D*>(pb); D*pd2 = dynamic_cast<D*>(pb); }
但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),
而pd2将是一个空指针。
另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。
这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(
关于虚函数表的概念,详细可见<Inside c++ object model>)中,只有定义了虚函数的类才有虚函数表,
没有定义虚函数的类是没有虚函数表的。
交叉转换
class A { public: int m_iNum; virtual void f(){} }; class B:publicA { }; class D:publicA { }; void foo() { B*pb = newB; pb->m_iNum = 100; D*pd1 = static_cast<D*>(pb);//compileerror D*pd2 = dynamic_cast<D*>(pb);//pd2isNULL deletep b; }
在函数foo中,使用static_cast进行转换是不被允许的,将在编译时出错,而使用 dynamic_cast的转换则是允许的,结果是空指针。
#include <iostream> using namespace std; class base{ public: virtual void f(){cout<<"base::f"<<endl;} void f1(){cout<<"base::f1"<<endl;} private: double x, y; }; class derived:public base{ public: virtual void f(){cout << "derived::f"<<endl;} virtual void k(){cout<<"derived::k"<<endl;} private: double z; }; class base1{ public: virtual void g(){cout<<"base1::g"<<endl;} void g1(){cout<<"base1::g1"<<endl;} }; class derived1:public base,public base1{ public: virtual void f(){cout<<"derived1::f"<<endl;} virtual void h(){cout<<"derived1::h"<<endl;} }; void test(){ // 对于单继承 // 如果 pd 真的指向Derived,用dynamic_cast 和 static_cast 效果相同 base *pd = new derived; derived *pd1 = dynamic_cast<derived*>(pd); pd1->f(); pd1->k(); pd1->f1(); //但是如果pb不是挣得指向derived,则用dynamic_cast 则返回null,能够更早的禁止error的发生, //但是用static_cast虽然返回的不为null,但是运行是可能抛出exception ///error code /* base *pb = new base; derived *pd3 = static_cast<derived*>(pb); pd3->f(); pd3->k(); pd3->f1(); derived *pd4 = static_cast<derived*>(pb); pd4->f(); pd4->k(); pd4->f1(); */ } void test2(){ //对于多继承 //如果pd 真的指向的是derived1, 使用dynamic_cast 和 static_cast 都可以转化为derived1, //但是如果要转化为base 的兄弟类base1,必须使用dynamic_cast ,使用static_cast不能编译。 base *pd = new derived1; derived1 *pd1 = dynamic_cast<derived1*>(pd); pd1->f(); pd1->h(); pd1->f1(); base1 *pb1 = dynamic_cast<base1*>(pd); pb1->g(); derived1 *pd2 = static_cast<derived1*>(pd); pd2->f(); pd1->h(); pd2->f1(); // error code : can't compiler // base1 *pb2 = static_cast<base1*>(pd); // pb2->g(); // 对于pb 不是真的指向derived1,想要转化为derived1或base 的兄弟类base1,情况与test1中的error情况 // 相同 } int main(){ test(); putchar(' '); test2(); return 0; }
3)const_cast<T*>(a)
4)reinterpret_cast<T*>(a)