BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #25813同步于 2009/7/3
CPP机器人发帖

关于dynamic_cast的标准及在vc6与gcc的实现

cymvp
2009/7/3镜像同步0 回复
dynamic_cast因为老不用,所以总是忘,今天又看了看标准,总结了下,就想贴出来,希望和大家交流,如果有不对之处,欢迎指教! 一 首先说一下c++标准的规定: dynamic_cast<T>(v) 1 如果T为base class, v为T的drived class,且T对于v类 为public且unambiguous的,则同强制向下转换: struct B {}; struct D : B {}; void foo(D* dp) { B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp; } 2 否则,v为指向多态类的指针,应该使用run-time机制决定转换。 1 如果v指向T类对象的某个public基类子对象,且T类对象中只有一份v的子对象,那么转换的结果为指向T类对象的指针。T为v指向对象的派生类。 D d; B *pb = &d; B *pb = dynamic<D*>(pb); /* B必须为多态类! */ 2 如果v指向某个派生类(比如X类)中某个public基类子对象,T为该派生类X的另一个(可以不同于v)的public且unambiguous的基类,则转换的结果为指向T类对象的指针。 class D: public A, public B; A pa = &d; B* pb = dynamic<B*>(pa); /* A必须为多态类! */ 3 否则, run-time check 会失败. 二 下面讲讲vc6和gcc的实现。 1 首先讲下 class D: public A, private B; D d,*pd; B* bp = (B*)&d; class D: public A, private B; bp = dynamic_cast<B*>(ap); (A是多态类) 对于上面这句,标准明确说明应该转换失败。 vc6只是给出个编译的警告,而gcc会在执行转换时返回失败,所以gcc更符合规范,虽然vc6知道标准的规定,但是没有实现。 2 再讲下比较tricky的做法: class D: public A, public B; D d,*pd; B* bp = (B*)&d; A* ap = &d; char *pp = (char*)ap; ap = dynamic_cast<A*>((B*)pp); /* B为多态类 */ 上面这句话其实很有意思,可以在vc6和gcc中分别试一下,可以看到vc6可以转换成功而且结果正确,而gcc转换失败。从中可以看出: vc6在run-time执行实际转换时,并不会考虑v的类型,而是根据v指向的内存地址,取出多态类信息,然后转换。也就是说vc6编译器会将派生类对象(比如X)中的每个基 类子对象的virtual函数表中都记录关于类X的信息(如:当前地址到对象基地址的偏移),这样就不用依赖v的类型就可以进行成功转换。 而gcc在run-time执行实际转换时,会检查v的类型,看v的类型与当前v指向的地址中记录的类型是否v一致,若一致,则进行转换,否则转换失败。也就是说gcc编译器在派 生类对象的每个基类子对象的virtual函数表中记录的可能是:当前基类子对象的类型,而非当前地址到类对象首地址的偏移量。 3 最后说一下同类型转换: class D : public A, public B {}; ap = dynamic_cast<A*>(ap); 对于这个转换,vc6要求A为多态类,而gcc则不会做要求。为什么呢? 原来c++标准还有这么一句: If the type of v is the same as the required result type,the result is v (converted if necessary). 也就是说,如果v和T的类型一致,那么进行的就是简单转换,而非run-time时转换!所以不要求A是多态类才是正确的。
订阅后,新回复会通过你的通知中心匿名送达。
0 条回复
暂无回复 · 你可以订阅本帖等待新回复。