免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1248 | 回复: 6
打印 上一主题 下一主题

为什么可以这样转换而不出错呢? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-08-29 16:58 |只看该作者 |倒序浏览
请问为什么在以下代码中,把本来是指向B的指针,转成了指向B的子类C的指针,结果却能好像正常工作。
在C中我又新加了一个成员变量i, 可这个变量在B中根本没有,然而,转换了之后好象能够把本来是B的当作C来对待。

谢谢!代码在下面

#include <iostream>
using namespace std;

class A {
public:
        virtual void f() const {}
};

class B : public A {
public:
        void f() const {}
};

class C : public B {
        int i;
public:
        void f() const {}
        void g() {
                i = 100;
                cout << i << endl;
        }
};

A * arr[2] = { new B, new C };

int main() {
        (static_cast<C*>(arr[0]))->g();
}


output from g++:
100

论坛徽章:
0
2 [报告]
发表于 2006-08-29 17:38 |只看该作者
  1. #include <iostream>
  2. using namespace std;

  3. class A {
  4. public:
  5.         virtual void f() const
  6.         { cout << "class A" << endl; }
  7. };

  8. class B : public A {
  9. public:
  10.         void f() const
  11.         { cout << "class B" << endl; }
  12. };

  13. class C : public B {
  14.         
  15. public:
  16.                 int i;
  17.        
  18.         void f() const
  19.         { cout << "class C" << endl; }
  20.         void g(int v) {
  21.                 i = v;
  22.                 cout << i << endl;
  23.                
  24.                 cout << "&i=" << &i << endl;
  25.         }
  26. };

  27. A * arr[2] = { new B, new C };

  28. int main()
  29. {
  30.         cout << "sizeof(B)=" << sizeof(B) << ",  sizeof(C)=" << sizeof(C) << endl;
  31.        
  32.         cout << "arr[0]=" << arr[0] << ",  arr[1]=" << arr[1] << endl;
  33.         (static_cast<C*>(arr[0]))->g(99);
  34.         
  35.         arr[0]->f();
  36. }
复制代码


运行的结果是:
sizeof(B)=4,  sizeof(C)=8
arr[0]=0x3d2448,  arr[1]=0x3d24b0
99
&i=0x3d244c
class B

arr[0]指向对象的大小是4,arr[0]的起始地址是0x3d2448,而调用 (static_cast<C*>(arr[0]))->g(99) 往变量i赋值,i的地址是 0x3d244c,已经超出了 arr[0]对象的范围。所以这个调用 (static_cast<C*>(arr[0]))->g(99) 是绝对错误的。

那为什么运行没有出错呢?因为 &arr[0]=0x3d2448,  &arr[1]=0x3d24b0,在arr[1]和arr[0]之间有一段空白的内存,这段内存虽然没有经过分配,但是却是可读写的。所以虽然(static_cast<C*>(arr[0]))->g(99)写到了错误的地方,却幸运的没有引起异常.................

论坛徽章:
0
3 [报告]
发表于 2006-08-29 17:41 |只看该作者
是啊,即使你写到了不该写的地方,程序也未必会core dump.
所以这种错误很难查的。

论坛徽章:
0
4 [报告]
发表于 2006-08-29 17:49 |只看该作者
(static_cast<C*>(arr[0]))->g();

这里用的不合适吧.像你的这种向下的依据运行时期类型信息的转换,应当用
(dynamic_cast<C*>(arr[0]))->g();

c++的3中显式转换方式还是有区别的.

reinterpret_cast
static_cast
dynamic_cast
是分别应用于不同场合的,D&E里面有较详细的说明.不知道你用的是什么编译器,如果是vc6之类的话,还是找一个严肃点的编译器吧.

论坛徽章:
0
5 [报告]
发表于 2006-08-29 18:07 |只看该作者
他就是要故意写错,呵呵~

论坛徽章:
0
6 [报告]
发表于 2006-08-29 18:11 |只看该作者
纯属侥幸,把优化等级调高试试

论坛徽章:
0
7 [报告]
发表于 2006-08-30 11:33 |只看该作者

回复 2楼 prc 的帖子

谢谢大家
是我自己把以下地址间当成了只有4个字节了(其实是16个),我就在想越过为VPTR分配的4个字节,就到了C的区域了,又对内存进行了写操作居然没出错。
0x6f0248
0x6f0258
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP