父类引用指向子类对象是什么意思_你知道子类引用为什么不能指向父类对象吗?反汇编一起看看...

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

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

0f545c3ea38f7a3a306d787226437576.png

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

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

94389c5cb36522c0d70853c62f7449e1.png

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

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

236d73c794f49ee025ec1f8d96e7f985.png

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

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

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

4fbcc216d28f53306024f763c3cbacdb.png
e89adb0a3125f6bf28993e63f969f408.png

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

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

ec6cebf40d8bec8888f7e606c534f013.png
3e787f3f0a1ab99826ecf244e693d6bd.png
625f3717d228d362a49c84e8c86a394e.png

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值