static_cast与dynamic_cast转换

一 C语言中存在着两种类型转换:html

隐式转换和显式转换安全

隐式转换:不一样数据类型之间赋值和运算,函数调用传递参数……编译器完成函数

char ch; int i = ch;

显示转换:在类型前增长 :(Type)变量 对变量进行的转换。用户显式增长spa

char *pc = (char*)pb; void *ps = (void*)pa;


二 C++
中的类型转换指针

  经过这两种方式,C语言中大部分的类型转换均可以顺利进行。code

至于能不能进行转换,转换后的结果如何,编译器无论须要用户本身去控制。htm

  C++继承了C中的隐式和显式转换的方式。但这种转换并非安全和严格的,对象

加上C++自己对象模型的复杂性,C++增长了四个显示转换的关键字。(C++是强类型语言)blog

static_castdynamic_castconst_staticreinterpret_cast继承


1 static_cast

(1)用于基本的数据类型转换(char,int),及指针之间的转换

复制代码
test_enum type = test_enum_1; char a ; int b = static_cast<int>(a); char c = static_cast<char>(b); type = static_cast<test_enum>(b); char* pa = NULL; int *pb = (int*)pa; //int *pb = static_cast<int*>(pa); //error //pa = static_cast<char*>(pb) //error
char *pc = (char*)pb; //char *pc = static_cast<char*>(pb); //error  void *p = static_cast<void*>(pa); pb = static_cast<int*>(p); pc = static_cast<char*>(p);
复制代码


(2)类层次中基类与子类成员函数指针的转换

 

复制代码
class A { public:  void set(){} }; class B:public A { public:  void set(){} }; typedef void (A::*PS_MFunc)();   //指向类A的成员函数指针  PS_MFunc func = &A::set; func = static_cast<PS_MFunc>(&B::set); //基类指向子类成员函数指针,必须进行转换
复制代码


(3)类层次结构中基类与子类指针或引用之间的转换  

   上行转换:子类指针或引用转换成基类表示——安全

  下行转换:基类指针或引用转换成子类表示——危险(没有动态类型检查)

复制代码
class A { }; class B:public A { }; class C:public A { }; class D { }; A objA; B objB; A* pObjA = new A(); B* pObjB = new B(); C* pObjC = new C(); D* pObjD = new D(); objA = static_cast<A&>(objB); //转换为基类引用  objA = static_cast<A>(objB); objB = static_cast<B>(objA); //error 不能进行转换   pObjA = pObjB;  //right 基类指针指向子类对象 //objB = objA; //error 子类指针指向基类对象 pObjA = static_cast<A*>(pObjB); //right 基类指针指向子类 pObjB = static_cast<B*>(pObjA);  //强制转换 OK 基类到子类 //pObjC = static_cast<C*>(pObjB); //error 继承于统一类的派生指针之间转换 //pObjD = static_cast<D*>(pObjC); //error 两个无关联之间转换
复制代码


2 dynamic_cast

(1)继承关系的类指针对象或引用之间转换

        

复制代码
class A { }; class B:public A { }; class C:public A { }; class D { }; A objA; B objB; A* pObjA = new A(); B* pObjB = new B(); C* pObjC = new C(); D* pObjD = new D(); //objA = dynamic_cast<A>(objB); //error 非引用  objA = dynamic_cast<A&>(objB); //objB = dynamic_cast<B&>(objA); //error A 不是多态类型不能转换 如有虚函数则能够进行转换  pObjA = dynamic_cast<A*>(pObjB); //pObjB = dynamic_cast<B*>(pObjA); //error A 继承关系 不是多态类型不能转换 //pObjB = dynamic_cast<B*>(pObjC); //error C 兄弟关系 不是多态类型不能转换 //pObjB = dynamic_cast<B*>(pObjD); //error D 没有关系 不是多态类型不能转换
复制代码

 

 

(2)包含有虚函数之间对象指针的转换   

复制代码
class A { Public:  Virtual ~A(){} }; class B:public A { }; class C:public A { }; class D { Public: Virtual ~D(){} };
pObjB = dynamic_cast<B*>(pObjA); // worning 继承关系 父类具备虚函数 多态 pObjB = dynamic_cast<B*>(pObjD); //worning 没有关系 D是多态类型能够转换 //以上结果:pObjB == NULL 此处会发生一个运行时错误
复制代码

         也就是说除了基类指针指向子类对象,能够没有虚函数外,其它要进行dynamic_cast转换必须具备虚函数才行。

那这是为何呢?下面继续>


(3)dynam_cast转换的安全性

         dynamic_cast是动态转换,只有在基类指针转换为子类指针时才有意义。

(子类指针转换为基类指针原本就是能够的:基类指针指向子类对象OK)。

可是基类指针转换为子类指针,并非每一次都有效:只有基类指针自己指向的是一个派生类的对象,

而后将此基类指针转换为对应的派生类指针才是有效的。这种状况在表面上是没法断定的。此时dynamic就发挥了做用。

状况1: static_cast转换       

复制代码
class A { };
class B:public A { public:  int m; //B 成员 }; A* pObjA = new A(); B* pObjB = NULL; pObjB = static_cast<B*>(pObjA); //基类指针转化为子类指针 成功转换 pObjB->m = 10;   //实际中pObj所指向的对象 是A类对象 //上面会发生什么呢,在VC6.0中正常运行。。。?  //若是: pObjB = dynamic_cast<B*>(pObjA); //error 基类A没有虚函数 不构成多态
复制代码

状况2:     dynamic_cast转换    

复制代码
class A { public:  virtual ~A(){}  //虚函数 多态 }; class B:public A { public:  int m; }; A* pObjA = new A(); B* pObjB = NULL; pObjB = dynamic_cast<B*>(pObjA); //编译经过 //实际运行结果:pObjB == NULL // dynamic_cast保证转换无效 返回NULL
复制代码

         dynamic_cast转换不成功,则返回0

4 虚函数对于dynamic_cast转换的做用

  为什么使用dynamic_cast转换类指针时,须要虚函数呢。

Dynamic_cast转换是在运行时进行转换,运行时转换就须要知道类对象的信息(继承关系等)。

如何在运行时获取到这个信息——虚函数表。

  C++对象模型中,对象实例最前面的就是虚函数表指针,

经过这个指针能够获取到该类对象的全部虚函数,包括父类的。

由于派生类会继承基类的虚函数表,因此经过这个虚函数表,咱们就能够知道该类对象的父类,在转换的时候就能够用来判断对象有无继承关系。

  因此虚函数对于正确的基类指针转换为子类指针是很是重要的。

相关文章
相关标签/搜索