北邮人论坛学术科技C/C++程序设计语言 → Re: 求大牛帮忙

     
本主题贴数1   分页: 1

 * 文章主题: Re: 求大牛帮忙  
  jokerlee
  
  昵称:Jackal The Dire
  等级:版主
  文章:2096
  积分:579
  星座:水瓶座 水瓶座
          楼主
发信人: jokerlee (Jackal The Dire), 信区: CPP
标  题: Re: 求大牛帮忙
发信站: 北邮人论坛 (Wed Dec 30 05:04:06 2009), 站内
 
这是一个Very Triky的问题...搞了一个多小时....万恶的函数式转型...jmpesp你真的搞的清楚么...
 
 
 
首先输出C是确定的,因为无论怎么转型, p都是指向一个C对象,而A、B中的fun都是虚函数,所以调用的肯定是C类方法
 
输出float看起来比较奇怪,原因是因为(B*)(A*)这个淫荡的、万恶的c-style转型
     cout << (A*)p << endl;
     cout << (B*)p << endl;
     cout << (B*)(A*)p << endl;
得到以下输出:
00382E30
00382E34
00382E30
可见(B*)(A*)p 和 (A*)p是相同的
这是因为,C继承了A和B,所以一个C对象里包含了一个A对象和B对象。(A*)p使得p偏移到了C对象中的A对象, 接下来(B*)再对指向A对象的p进行转型,这时候问题就出现了,B对象并不包含A对象,编译器也不知道p指向的A对象实际上是包含在一个C对象里,所以(B*)这次转换,只是改变了p的静态类型,并没有改变p指向的位置,也就是说p还是指向一个A对象。所以通过p调用fun(1)的时候,查的是A的虚表,先查到virtual void A::fun(float),再到void C::fun(float)
 
 
这个问题的关键就在(B*)(A*)p这两个C-Style的函数式转型(functional cast)上:
(A*)p是从派生类C到基类A的转换,有可能是是个向上的static_cast,也有可能是个简单的reinterpret_cast, 从上面的分析结果上看(A*)是个static_cast的up cast,而由(A*)到(B*)的转换不可能是static_cast(static_cast<B*>(static_cast<A*>(p)))是编译不过的),所以只能是reinterpret_cast
 
这里又出现了一个问题,为什么(A*)p是个static_cast而不是reinterpret_cast?至少这与我的直觉不服,在ISO C++标准5.4节找到如下定义(见图)
 
 
 
也就是说一个C-style的强制类型转换如果可以解释成多个列表里的C++ style转型,取在列表里位置最前面的一个。static_cast在reinterpret_cast前,所以得到了下面的结果:
 
(B*)(A*)p 等价于 reinterpret_cast<B*>(static_cast<A*>(p))
 
由这道题目说明,千万不要用C-style对对象指针进行转型,请用C++-style的static_cast、reinterpret_cast和dynamic_cast
 
Over.
--
 
※ 修改:·jokerlee 于 Dec 30 11:23:56 2009 修改本文·[FROM: 2001:da8:215:8206:4bc:6d3c:ef9c:*]
※ 来源:·北邮人论坛 http://forum.byr.edu.cn·[FROM: 2001:da8:215:8206:b8bc:d3c1:51f2:*]
本主题贴数1   分页: 1

  快速发表新帖子
主题标题   *不得超过 25 个汉字或50个英文字符
内容
选项   [查看签名档]
   

  
Powered by wForum Version 0.9
阿卡信息技术(北京)有限公司 & KBS 开发组 版权所有 2005-2006
wForum @zixia.net , 页面执行时间:20.088毫秒