简单整理了下该知识点。
它们一个动态转换,一个是静态转换。
dynamic_cast是试探映射,如dynamic_cast<A>*pB意思是“我希望它是A*,并打算要求它是”。它通常被称为类层次的动态导航。
static_cast通常可用于类层次的静态导航,无映射变换,窄化变换(会丢失信息)等等,static_cast的应用要广一些,但如前所提到的,在类层次导航变换中我们应该使用前者,因为后者static_cast可能意味着冒险(比如变换时类似于强制转换一样丢失信息)。但是在一个类层次中没有虚函数或者我们确定有其他允许我们安全向下映射的信息则后者static_cast更快一些。
下面具体介绍下dynamic_cast
理解C++ dynamic_cast
C++程序员大多喜欢使用强制类型转换(我也是),尽管它是C遗留下来的,尽管它存在这样那样的缺点,但是你不能不承认它使用起来很方便,而且绝大多数情况下是不会产生问题的.极少数情况下可能会存在类型转换失败的情况,这时候就需要使用到dynamic_cast了,这里提到的"极少数情况"是这样的:如果有继承或多重继承的类对象,你在某些情况下得到某个对象的指针,而你又想将其转换为某个特定类型,但是由于C++中对象类型的多态性(它可以是多种类型),你又不能确定(在运行时)这么做一定会成功,此时可以使用dynamic_cast,充分利用C++的运行时检查机制.
基本功能
dynamic_cast <type-id> (expression)
该运算符把expression转换成type-id类型的对象。Type-id 必须是类的指针、类的引用或者void*;
如果 type-id 是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用。
基本用法
dynamic_cast可以获取目标对象的引用或指针:
T1 obj;
T2* pObj = dynamic_cast<T2*>(&obj);//转换为T2指针,失败返回NULL
T2& refObj = dynamic_cast<T2&>(obj);//转换为T2引用,失败抛出bad_cast异常
多态类型
在使用时需要注意:被转换对象obj的类型T1必须是多态类型,即T1必须公有继承自其它类,或者T1拥有虚函数(继承或自定义)。若T1为非多态类型,使用dynamic_cast会报编译错误。下面的例子说明了哪些类属于多态类型,哪些类不是:
//A为非多态类型
class A{
};
//B为多态类型
class B{
public: virtual ~B(){}
};
//D为多态类型
class D: public A{
};
//E为非多态类型
class E : private A{
};
//F为多态类型
class F : private B{
}
横向转型
在多态类型间转换,分为3种类型:
1.子类向基类的向上转型(Up Cast)
2.基类向子类的向下转型(Down Cast)
3.横向转型(Cross Cast)
向上转型是多态的基础,需不要借助任何特殊的方法,只需用将子类的指针或引用赋给基类的指针或引用即可,当然dynamic_cast也支持向上转型,而其总是肯定成功的。而对于向下转型和横向转型来讲,其实对于dynamic_cast并没有任何区别,它们都属于能力查询。为了理解方便,我们不妨把dynamic_cast视为cross cast:
class Shape {
public: virtual ~Shape();
virtual void draw() const = 0;
};
class Rollable {
public: virtual ~Rollable();
virtual void roll() = 0;
};
class Circle : public Shape, public Rollable {
void draw() const;
void roll();
};
class Square : public Shape {
void draw() const;
};
//横向转型失败
Shape *pShape1 = new Square();
Rollable *pRollable1 = dynamic_cast<Rollable*>(pShape2);//pRollable为NULL
//横向转型成功
Shape *pShape2 = new Circle();
Rollable *pRollable2 = dynamic_cast<Rollable*>(pShape2);//pRollable不为NULL
指针比较
接上面的例子,在我的机器上pShape2和pRollable2的值(所指向的地址)分别为:
pShape2: 0x0039A294, pRollable2:0x0039A290
说明dynamic_cast在进行转型的时候对不同多态类型设置了不同的偏移量。接下来的问题是
pRollable2 == pShape2
这个表达式应该返回什么呢?答案是:1,即指针比较相等。也许从C语言转到C++的朋友可能会感到困惑,因为在C语言中指针的比较只是值比较而已。显然,对于多态类型,C++编译器为==运算符做了更多的幕后工作来保证指针比较注重对象的同一性而非指针的值。至于实现细节涉及到C++对象模型,这是我还不甚熟悉的内容,故本文不再深入。
/*下面从网上摘下的例子,主要讲述了 dynamic_cast<> 的使用方法。*/
/*作用:将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理,
即会作一定的判断。
对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;
对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。
注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数。例如在下面的代码中将CBasic类中的test函数不定义成
virtual时,编译器会报错:error C2683: dynamic_cast : “CBasic”不是多态类型
对编译器的要求:
dynamic_cast<> 会用到RTTI技术,因此需要启动“运行时类型信息”这一选项,而在VC.net 2003中默认是关闭的。
所以需要人为的启动这一选项。否则编译器会报下面的警告:
warning C4541: “dynamic_cast”用在了带 /GR- 的多态类型“CBasic”上;
可能导致不可预知的行为从而导致程序在运行时发生异常。
该设置在 Project->Setting中 C/C++ -> C++ Language中设置。
*/
#include <iostream>
using namespace std;
class CBasic
{
public:
virtual int test(){return 0;} // 一定要是 virtual
};
class CDerived : public CBasic
{
public:
virtual int test(){ return 1;}
};
int main()
{
CBasic cBasic;
CDerived cDerived;
CBasic * pB1 = new CBasic;
CBasic * pB2 = new CDerived;
//dynamic cast failed, so pD1 is null.
CDerived * pD1 = dynamic_cast<CDerived * > (pB1);
//dynamic cast succeeded, so pD2 points to CDerived object
CDerived * pD2 = dynamic_cast<CDerived * > (pB2);
//dynamci cast failed, so throw an exception.
// CDerived & rD1 = dynamic_cast<CDerived &> (*pB1);
//dynamic cast succeeded, so rD2 references to CDerived object.
CDerived & rD2 = dynamic_cast<CDerived &> (*pB2);
return 0;
}