前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么子类引用不能指向父类对象

为什么子类引用不能指向父类对象

作者头像
xujjj
发布2020-05-18 14:46:56
2.7K0
发布2020-05-18 14:46:56
举报
文章被收录于专栏:IT界的泥石流

在java、C++等面向对象的语言中,实现多态的方式就是使用父类引用指向子类对象,所以父类引用指向子类对象是没有任何为题的,但是,大家有没有想过,子类引用可以指向父类对象吗?答案是不可以!但是为什么呢?

下图是在java中,使用子类引用指向父类对象的情况

编译可以通过,因为对生成的Person对象做了一个强制转换,骗过了编译器,其本质上还是属于子类引用指向父类对象。

点击运行,出现下图的报错情况。

很明显,java虚拟机在运行该行代码的时候进行了运行时检测,禁止子类引用指向父类对象。

所以,这种操作在java里面是不允许的,接下来,我们把代码拷贝一下,在C++的环境再跑一下。

编译,运行,一切非常顺利。

为什么java里面不允许这种操作,而C++却允许这种操作呢?我们接下来在C++的环境下,反汇编窥探一下这写代码究竟干了些什么事。

首先,在执行这行代码的时候,先把一个4压入栈中,然后去调用operator new这个函数,很明显,这个4就是该函数的一个参数,它完成的任务就是,向堆空间申请4个字节的存储空间,为什么是4个字节?因为Person这个类里面只有age这一个属性,因此new出来的对象也只需要4个字节存储就够了。然后使用stu这个Student类型的指针指向这4个存储空间的首地址。

接下来,我们来看一下,下面两行的反汇编代码,因为Student类继承于Person类,因此Student类里面有age和stuId两个变量,又因为是公有的,所以stu可以访问这两个变量的地址,我们对这两个值进行赋值操作。

这两个赋值操作的反汇编代码如下,可以明显看出,它们都是先找到stu指向的Person对象的堆空间首地址,然后当给age赋值为18时,是把12h(18的十六进制)塞给Person对象首地址位置开始的4个字节,当给stuId赋值为2时,是把2(2的十六进制)塞给Person对象首地址+4位置处开始的4个字节,

大家可以看到上图,很明显,相信大家就看出问题来了。。

因为new Person()只申请了4个字节的存储空间,而你现在却越界使用了没申请到的后面4个字节存储空间,然后把2赋值给了这4个字节的存储空间中。

这会导致什么问题?因为后面的这4个字节没有被你申请到,那么该4个字节可能是其他的一些数据,那么你的这个行为会覆盖掉别的数据,或者这4个字节还是空闲的,以后可能被其他的数据覆盖,所以这是一种不安全的行为。

因此,无论在C++还是java中,都是应该禁止掉这种行为的,只是java做了运行时检测,而C++并没有而已。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 IT界的泥石流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档