为什么父类指针可以指向子类反之则不行?

为什么父类指针可以指向子类反之则不行?

例如:
class a
{public:
int aa};
class b:public a
{public:
int bb;
}
从内存的来看
如a
---------|
|占一个int数据大小--|
|----(aa数据)------|
|---------
而b则是
---------|---------
|占一个int数据大小--|占一个Int数据大小--|
|从a中继承而来------|---(bb数据----------|
|------------------

当定义一个基类类型的指针时
a *p;这时,这个指针指向的是a类型的数据
当p指针指向派生类的时候,因为p是a类型的指针,所以*p只解释为a类型数据的长度,即
————————-|---------
|占一个int数据大小--|占一个Int数据大小--|
|从a中继承而来------|-----(bb数据)-------|
|------------------
|------------|------------|
|-p只指向这个区域_--|



因此,当基类的指针(P)指向派生类的时候,只能操作派生类中从基类中继承过来的数据。

指向派生类的指针,因为内存空间比基类长,会导致严重了后果,所以不允许派生类的指针指向基类。而基类的指针可以指向派生类。

C++的多态性能解决基类指针不能操作派生类的数据成员的问题。

 

举报
通常来说,子类总是含有一些父类没有的成员变量,或者方法函数。而子类肯定含有父类所有的成员变量和方法函数。所以用父类指针指向子类时,没有问题,因为父类有的,子类都有,不会出现非法访问问题。
但是如果用子类指针指向父类的话,一旦访问子类特有的方法函数或者成员变量,就会出现非法,因为被子类指针指向的由父类创建的对象,根本没有要访问的那些内容,那些是子类特有的,只有用子类初始化对象时才会有。


父类指针指向的子类实例是什么?其实就是多态的表现。其中多态的静态表现是运算符和函数的重载(这些都是在编译的时候就确定的)。但是父类子类的虚函数可实现动态的多态性--即是运行时候的多态性

       为么能这样指着呢?这个得和为么不能反过来指向辨析。首先就得扯远一点,指针类型是用来干嘛的?标记指针所指向区域的大小。如果指向的区域小而且本身指针大(这里的大小是相对与内存空间而言的),那就出来的数据是有问题的,不是越界访问就是随机码。但是反过来,就不会出现越界访问的问题。回到正题,父类指针显然是个小内存,子类显然是大内存

首先小内存的指针指向大内存的地点就是个很正常的事情(反过来就不行),当然反过来指向也没问题,强制类型转换是都可以做到的。第二点是由于父类指针指向子类中父类的函数或者变量,能够完全的对应,反过来子类的函数就无处可调用了。

再说起这个有什么用,一般来说,一个对象实例创建完就定死了,万一以后发生变化就要改代码了。那么事先就不写死子类,而是写父类,那么以后用到父类的地方,用子类实例,或者grand子类实例都可以取代,不用改实例名了




父类指针指向子类的实例:
  1. 无论父类里面有没有虚函数,都可以定义指向子类实例的父类指针.

  2. 如果父类里没有虚函数,则使用父类指针,只能访问父类的成员,而不能访问子类里的成员.

  3. 如果父类里的虚函数不是纯虚函数,且子类里没有重写该虚函数,则用父类指针访问该虚函数的时候,跟访问父类里的普通函数一样.

  4. 如果父类里的虚函数不是纯虚函数,且子类里重写了该虚函数,则用父类指针访问该虚函数的时候访问的是子类里重写后的函数.

  5. 如果父类里的虚函数是纯虚函数,则父类是个抽象类,子类要想能够被实例化,则必须重写该纯虚函数.用父类指针访问该纯虚函数的时候,访问到的是子类里重写了的函数.

  6. 再有一个要注意的是析构函数要声明为虚函数,这样在delete父类指针的时候,才会调用实例化的子类的虚函数,否则只会调用父类的析构函数,造成子类的剩余部分没被释放,从而造成内存的泄漏.

     

    总结:

    当定义一个指向子类实例的父类指针的时候,内存中实例化了子类,由于子类继承了父类,因此内存中的子类里包含父类的所有成员.但由于生命的时父类指针,因此该指针不能够访问子类的成员.而只能访问父类的成员.然而在父类里可以声明纯虚函数和定义虚函数.使用父类指针访问虚函数或纯虚函数的时候,访问到的是子类里重写的函数当然,对于虚函数,如果子类里没有对其重写的话,仍然访问到父类里定义的虚函数.可见虚函数和纯虚函数的却别仅仅在于:纯虚函数没有定义,只有声明,而且它使拥


C++用dynamic_cast将父类指针转换为子类指针,为什么不一定成功?

这个问题牵扯到c++的对象模型。一般认为子类对象大小>=父类对象大小。为什么?因为子类可以扩展父类,可以增加成员变量。如果一个子类增加了成员变量,那么它的对象的内存空间会大于父类对象。这时一个实际指向父类的指针,如果被强制转化为子类对象指针,当使用这个指针时可能会导致越界访问非法内存。相反,为何子类指针可以转换为父类指针?因为父类指针需要的,子类对象都有,不会出现非法内存访问。
这就是dynamic_cast不一定成功的原因。如果一个实际指向子类对象的指针被转换成了父类指针,然后再用dynamic_cast转换回来,一定能成功,而一个实际指向父类对象的指针,被dynamic_cast转换为子类指针,一定会失败。 


C++中父类和子类的指针互相指向

今天看C++的书,测试了一下父类和子类指针互相指向父类和子类的情况会发生的情况.(未使用虚函数)

父类指针指向父类本身,只能访问父类有的成员变量和成员函数.

子类指针指向子类本身,如果子类覆盖了父类有的成员变量和成员函数访问子类的成员变量和成员函数.如果子类没有覆盖父类的,则访问父类的成员变量和函数


若父类指针指向子类,编译器是可以通过的,该指针只能访问父类的成员变量和函数

若子类指针指向父类,编译器会报错,我们使用类型强转,将父类指针变为子类指针.此时我们再用子类指针时,我们可以发现,我们可以用子类指针访问任意子类的成员变量和成员函数.哪怕该指针实际指向的时一个父类的对象.

这一度使自己比较迷惑,后来经过研究,得出结论.因为该指针的类型已经转化为子类指针,所以所有操作都会被看为子类,包括成员函数和成员变量.对于成员函数,函数的存储地址使在代码段,所以直接可以访问.至于成员变量,编译器会将子类指针指向的地址当成一个子类的内存分布来对待,哪怕该段地址上只是一个父类的对象,也就是说,如果访问了子类中有而父类没有的对象,那么其实指针的访问已经越界了,可能已经修改了其他变量的值了,这样是很危险的.

综上所述,其实不管父类和子类的指针如何指向互相的对象,编译器的操作只会按照指针的类型来做出相应的动作.如果是一个子类指针,无论指向的地址是不是父类,哪怕是一个int型变量的地址,也会按照一个子类的内存分布去操作.父类指针同理.因此在操作C指针时要特别注意.

参考链接:http://blog.sina.com.cn/s/blog_523491650100i46c.html

                   http://blog.csdn.net/songzi1111/article/details/12350109

                   http://baike.1688.com/doc/view-d35951410.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值