dynamic_cast介绍

来源:互联网 发布:云计算的具体应用实例 编辑:程序博客网 时间:2024/06/06 01:13

dynamic_cast介绍

dynamic_cast<type-id> (expression)

这个表达式将 expression 转换为一个 type-id 类型的对象。 Type-id 必须是一个指针、指向一个已经定义类的类型或一个指向 VOID 的指针。Expression 的类型必须是一个指针,如果 type-id 是一个指针;当 type-id 是一个引用的时候必须是一个左值。

如果 type-id 是一个到 expression 类的直接或间接的模棱两可的指针,结果是一个到 type-id 类型的子对象:

class B { ... };

class C : public B { ... };

class D : public C { ... };

 

void f(D* pd)

{

   C* pc = dynamic_cast<C*>(pd);   // ok: C 是一个直接的基类

                                 // pc 指向 pd 的 C 子对象

 

   B* pb = dynamic_cast<B*>(pd);   // ok: B 是一个间接的基类

                                 // pb 指向 pd 的 B 子对象

   ...

}

这个类型转换叫做向上转型,因为它将一个指针在其继承层次向上转型,即从一个继承类到其基类。向上转型是隐式转换。

如果 type-id 是一个 void* ,运行时检查将决定表达式的实际类型。结果是一个到 expression 指向的完整对象。例如:

class A { ... };

 

class B { ... };

 

void f()

{

   A* pa = new A;

   B* pb = new B;

   void* pv = dynamic_cast<void*>(pa);

   // pv 指向一个 A 类型的对象

   ...

   pv = dynamic_cast<void*>(pb);

   // pv 指向一个 B 类型的对象

}

如果 type-id 不是 void* ,运行时检查指向 expression 的对象能否转换为指向 type-id 类型的对象。

如果 expression 类型是 type-id 的基类,运行时检查是否 expression 实际是一个指向 type-id 类型的完整对象,如果是,结果返回指向 type-id类型的完整对象,否则返回 NULL 。例如:

class B { ... };

class D : public B { ... };

void f()

{

   B* pb = new D;                     // unclear but ok

   B* pb2 = new B;

   D* pd = dynamic_cast<D*>(pb);      // ok: pb 实际指向 D

   ...

   D* pd2 = dynamic_cast<D*>(pb2);   // pb2 实际指向 B 而不是 D

                                    // 转换失败, pd2 是 NULL

   ...

}

向下类型转换之所以这么说是因为其从类继承层次的父类向子类转换。

在多重继承的情况,可能导致二义性。看一下下面的类继承层次:

H1.bmp


指向类型D的指针转换为B或C都正常,但如果从D转换到A将会怎么样来?这个结果导致转换的二义性错误;为了结果这个问题,你可以指向两次明确的转型,例如:

void f()

{

   D* pd = new D;

   A* pa = dynamic_cast<A*>(pd);      // 错误:二义性

   B* pb = dynamic_cast<B*>(pd);      // 首先转换到 B

   A* pa2 = dynamic_cast<A*>(pb);   // ok: 明确的

}

在使用虚基类的时候就导致更复杂的模糊;看下面的类层次图:

H2.bmp


在这个继承层次中,A是虚基类。假定一个类E的实例并且一个指向A子对象的指针,一次到B的dynamic_cast会由于不明确性导致失败,你必须首先转换到适当的层次,然后再向上转换到确定的层次,一直按照这种方式直到到达正确的B对象。

看下面的类层次图:

H3.bmp


假定一个类型E的对象和一个指向D子对象的指针,从D子对象导航到左上A子对象,必须执行三个转换。从D到E的dynamic_cast的转换,然后一个从E到B的转换(可以是dynamic_cast或者隐式转换),最终是从B到A的转换,例如:

void f(D* pd)

{

   E* pe = dynamic_cast<E*>(pd);// 这里的 D 实际上是 E 类型的对象

   B* pb = pe;      // upcast, implicit conversion

   A* pa = pb;      // upcast, implicit conversion

}

dynamic_cast 操作能执行交叉转换,使用上面相同的类层次,从 B 子对象到 D 子对象转换是可能的,只要完整的对象是 E 。

由于交叉转换,从 D 指针到左上角 A 子对象的指针是可行的;首先从 D 到 B 的交叉转换,然后隐式从 B 到 A 的转换。例如:

void f(D* pd)

{

   B* pb = dynamic_cast<B*>(pd);      // cross cast

   A* pa = pb;                  // upcast, implicit conversion

}

一个 NULL 指针值通过 dynamic_cast 转换到一个 NULL 指针。

当使用 dynamic_cast < type-id > ( expression ) 时, 如果 expression 不能安全的转换到 type-id ,运行时检查导致转型失败,例如:

class A { ... };

 

class B { ... };

 

void f()

{

   A* pa = new A;

   B* pb = dynamic_cast<B*>(pa);      // fails, not safe;

                                    // B not derived from A

   ...

}

转换失败的指针类型是 NULL 指针。失败的引用类型转换抛出 bad_cast_exception 异常;如果 expression 没有指向或引用一个有效的对象将抛出__non_rtti_object 异常。
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 医院发票法院要保险也要怎么办 上海社保里生育险暂停参保怎么办? 痔疮手术后大姨妈来了怎么办 微创痔疮术后第五天涨出血怎么办? 肚子胀疼大便拉不出来怎么办 得痔疮了该怎么办昆明东大治 下体痒还没去检查就来月经了怎么办 直肠造口手术后造口肠子突出怎么办 痔疮pph手术瘢痕两年了该怎么办 肛瘘挂线术后六天腹泻了怎么办 刚满月的孩子鼻子不通气怎么办 齐鲁医院挂的号晚了怎么办 手机微信安装后注册失败怎么办 舞蹈基本功胸怎么都转不动怎么办 饥荒手机版第10天遇到的狗怎么办 饥荒海难手游石墙老是放歪怎么办 小燕子从窝里掉下来了怎么办 二岁宝宝晚上睡觉不踏实怎么办 脚扭伤了有点痛但没肿该怎么办 落地扇的机头摇摆的地方坏了怎么办 跌倒在楼梯上右侧肋骨骆上怎么办 1岁3个月害怕自己不敢走路怎么办 苹果手机没开定位丢了怎么办 我和我老婆每天都吵架怎么办 现在在学注册消防师好枯燥怎么办 店铺台阶太高顾客不愿进来怎么办? 上古卷轴5跑步要沉下去怎么办 1岁半宝宝半夜醒来不睡觉怎么办 上古卷轴5不小心偷了东西怎么办 47牙缺失17号长长了怎么办 碎纸机过热件亮了卡住纸了怎么办 汽车买贵了2万多怎么办 宝宝眼皮被蚊子咬肿了怎么办 一岁宝宝撞头咬到舌头有伤口怎么办 二胎快生了老大特别粘人怎么办 生二胎不舍得大宝跟奶奶睡怎么办 怀二胎婆婆不帮忙带孩子怎么办 注册过的高铁用户名忘了怎么办 硕士延期毕业找好的工作怎么办 竞彩足球绑定信用卡提不了现怎么办 qq启动出现问题请卸载重装怎么办