当前位置:C++技术网 > 资讯 > 父类指针强制转换子类指针问题

父类指针强制转换子类指针问题

更新时间:2016-08-10 17:00:57浏览次数:1+次

问题一:父类指针比子类指针小。为什么父类指针还能强制转换为子类指针,而且子类指针还能访问子类的成员变量

问题二:父类指针强制转换为子类指针,父类指针的指向不变,子类指针指向父类指针指向的内存,那他们两个岂不是指向同一个内存区域了


C++技术网解答:

要想明白这个问题,主要在于理解指针、类型本质、类型与内存的关系以及虚函数重载实现的多态。

我们先来看一个类继承的内存模型示意图:

类继承的内存模型示意图

    三个类的继承关系如下:

class A
{
   //A的定义
}
class AA: public A
{
   //AA的定义
}
class AAA: public AA
{
   //AAA的定义
}
     如果每一次继承的类都增加了自己的变量和函数,那么派生类对象所占的内存会不断的变多。也就是上图所示的,内存占用叠加的意思。不同的类代表不同的类型,在内存中占用的大小和布局都可能不一样,而指向类对象的指针,也就是根据这个类的类型即内存布局和大小来决定指针的操作方式,在递增指针值时是按照指针类型的类的整个内存大小单元进行的。所以,不同的类的指针,指针的行为是不一样的。

    前面的类继承的内存模型作为解答的基本知识,下面开始一个个的说。

    所有的指针大小都是一样的,在32位系统中,指针大小值为32位,即4字节。而在64位系统中,指针大小为64位,即8字节。所以,“父类指针比子类指针小”得描述有错误。

    在C/C++语言中,类型的强制转换太正常也太常用了。类指针也是一个普通的指针而已,和整型指针没有多大区别,区别就在于指向类型的差别。你把类当做一个数据类型看就行了。

    而将父类指针强制转换为子类指针后,代表着指针的行为将会发生变化。从内存模型中可以看出,父类占用的内存小,子类即派生类占用的内存会多些,因为子类增加了一些东西,这些东西父类是没有的。父类指针开始只能操作父类的成员变量和成员函数。当转换为子类指针后,那么父类指针此时就不是父类指针了,而完全华丽变身为子类指针。所以此时的父类指针只能说它是由父类指针变成了子类指针,不再是父类指针了。这是我们程序员以为的,实际上,父类指针被强制转换后所得的指针是子类指针,所以,子类指针能访问子类的成员变量是再自然不过了。

    这和“将子类对象地址赋值给父类指针,从而父类指针可以访问子类成员函数有本质不同”。此时的父类指针只是指向不同,指针自己的类型并没有变化,此时能够调用子类的成员函数,是因为虚函数的重载形成的多态机制,如果调用的函数不是虚函数,还不能这样使用。

    而先将指向父类对象的父类指针转为子类指针,然后再赋值给子类指针,父类指针指向不变,他们确实指向的是同一个内存区域,而且是指向的父类对象的内存。因为子类的内存结构兼容了父类,也就是与父类重叠的一部分,和父类一样的内存结构,所以此时子类指针是可以操作父类对象的,没有任何问题。

    顺带提一句,这是常见的问题。如果将指向子类对象的子类指针强制转为父类指针,然后将子类指针赋值给父类指针,此时父类指针就指向的是子类对象。此时父类指针还是可以操作子类继承父类的可以访问的函数和变量,因为父类指针类型和子类中父类的那部分内存结构一致,可以正常操作。但是此时父类指针不能操作子类新增的函数和变量,因为父类类型没有子类新增的内容,所以子类的多出的内容是父类类型没有描述的,所以父类指针在没有类型描述即没有内存描述的地方,就懵逼了。父类指针只能活动在父类描述的范围之内。如果此时你将父类指针强转为子类指针,就可以操作子类,因为子类有描述多出的内容的结构等信息。

    始终记住一点,指针是根据指针的类型来操作,不同的类类型不同,即内存布局大小等不同,然后子类的内存布局包含了父类的部分,父类指针只能活动在父类的结构的内存范围中。

    这样了解清楚后,强制转换可以随心所欲,更改了指针的类型,也就让指针获得了不同的能力。转为父类指针,相当于把指针的操作范围缩小为父类的定义范围,此时子类多出的东西无法操作。转为子类指针,相当于把指针的操作范围扩大到子类描述的范围,含子类继承的父类的部分。继承的层次越多,最后一级的子类的指针类型可以操作的范围是最大的,最开始的父类操作范围是最小的。最小范围的父类就是纯虚函数组成的基类,也就是纯虚类的接口类。这个父类不能直接使用,必须继承派生子类使用,而且每一个纯虚函数都要重载一个可用的函数。

    这个提问涉及到继承中的指针的核心问题,如果看晕了,多读几遍,慢慢理顺。