一、父类指针指向子类对象

先上代码:

class Base
{public:void base_fun1() {}virtual void base_fun2() {cout << "this is Base fun2()" << endl;}
public:int a_a;
protected:int a_b;
private:int a_c;
};class Son :public Base
{public:void son_fun1() {}void base_fun2()//重写父类虚函数{cout << "this is Son fun2()" << endl;}
public:int b_a;
protected:int b_b;
private:int b_c;
};int main()
{Base* ba = new Son();//父类指针指向子类//父类指针只能访问从父类继承而来的成员变量和成员函数//只能访问从父类继承而来的成员变量ba->a_a = 10;//只能访问从父类继承过来的成员函数ba->base_fun1();//由于子类对象用的是从父类继承而来的虚函数表,所以父类指针可以通过查找父类虚函数表的方式,调用被子类重写后的函数ba->base_fun2();//子类指针对所有的成员变量和成员函数随意访问(受访问权限限制)Son* so = new Son();//子类指针指向子类so->a_a = 10;so->b_a = 10;so->base_fun1();so->son_fun1();so->base_fun2();so->Base::base_fun2();return 0;
}

so是子类指针,指向子类对象,可以通过so访问任何子类的东西。前提是在遵守访问权限限制的情况下。
ba是父类指针,指向子类对象,但是只能通过ba访问继承过来的成员变量和成员函数。也就是说,不能通过指向子类对象的的父类指针访问子类对象的本身的成员变量和成员函数。
ba可以访问子类对父类虚函数重写的函数。因为子类和父类共用一个虚函数表,子类用的是从父类继承过来的虚函数表(虚函数表问题点击此处),父类指针也只是通过父类的虚函数表查找函数地址,然后调用,之所以可以通过父类指针访问子类重写父类虚函数后的函数,根本上还是因为子类用的还是父类的虚函数表。
通过让父类指针和子类指针指向同一个子类对象,看一下这俩指针到底指向了哪里。我们都知道子类对象是个大空间,里面包括子类本身的成员变量,还包含一个小空间,小空间是父类的无名对象,被子类对象所拥有。如果没有虚继承的话,小空间的首地址和大空间的首地址是一起的,导致无法查看父类指针和子类指针的指向区别,如下图所示(对于继承和虚继承博客,点击此处):

但是虚继承就不一样了,虚继承的话,子类的本身变量成员在小空间上方。如下虚继承代码和子类对象空间结构图:
代码:

class Base
{public:void base_fun1() {}virtual void base_fun2() {cout << "this is Base fun2()" << endl;}
public:int a_a;
protected:int a_b;
private:int a_c;
};class Son :virtual public Base
{public:void son_fun1() {}void base_fun2()//重写父类虚函数{cout << "this is Son fun2()" << endl;}
public:int b_a;
protected:int b_b;
private:int b_c;
};int main()
{Son so;Base* baptr = &so;Son* soptr = &so;cout << "父类指针指向的空间首地址:" << (int)baptr << endl; cout << "子类指针指向的空间首地址:" << (int)soptr << endl;cout << "a_a的地址:" << (int)&so.a_a << "   " << "b_a的地址:" << (int)&so.b_a << endl;return 0;
}

运行结果:

子类对象空间结构图 :

所有的东西都在上面的图中。(可以通过vs的开发者工具查看类的对象的空间结构图)
上面的图展示了子类对象的空间结构图,含有指向子类对象的父类指针指向的空间,和指向子类对象的子类指针指向的空间。所以两个指针指向的空间的首地址不一样,指向子类对象的子类指针指向的空间包含指向子类对象的父类指针指向的空间。而父类指针指向的空间里面的东西,就是从父类继承而来的东西,所以只能通过父类指针访问从父类继承过来的成员变量,而能访问子类对象重写的函数,是因为子类用的是从父类继承过来的虚函数指针,用的虚函数表也是从父类继承而来的,父类指针可以通过父类的虚函数指针访问虚函数表,进而调用子类重写的函数。
当子类用保护继承或者私有继承的方式继承父类时,编译器就不允许父类指针指向子类对象了。因为父类指针本质上是指向子类对象空间里的从父类继承而来的那部分内容空间,而这部分内容用的是私有或者包含继承的方式,不允许随意访问,自然也不允许外部指针随意指向。但是在子类类内(成员函数内)可以,因为类内不受访问权限的限制,可以随意访问这些东西。
总结:
如果父类指针指向子类对象,那么只可以通过父类指针访问子类继承的父类的成员函数和成员变量。(遵守访问权限限制是前提,其次,由于子类继承了父类的虚函数指针,且子类用的也是父类的虚函数指针和虚函数表,所以父类指针可以通过查找父类虚函数表的方式调用被子类重写后的函数)。

二、父类对象和子类对象之间的问题

子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
但是反过来不行。
代码:

class Base
{public:void base_fun1() {}virtual void base_fun2() {cout << "this is Base fun2()" << endl;}
public:int a_a;
protected:int a_b;
private:int a_c;
};class Son :virtual public Base
{public:void son_fun1() {Son so;Base* baptr = &so;}void base_fun2()//重写父类虚函数{cout << "this is Son fun2()" << endl;}
public:int b_a;
protected:int b_b;
private:int b_c;
};int main()
{Base a;Son b;a = b;b = a;//errorreturn 0;
}

编译器会自动生成赋值函数,这个赋值函数和缺省拷贝构造函数可以说是做法一模一样。都是值拷贝(字节拷贝)。所以如果父类有指针而对象用继承的指针指向了堆空间的话,一定小心这个赋值语句,会造成两个指针指向一个堆空间的问题,这个时候要小心析构函数对一个堆空间进行两次释放的问题。这里不对这个问题再次进行讨论了。在构造函数的博客以及多态的博客中都有讲述产生的问题和解决办法。
为什么子类对象可以赋值给父类对象,而父类对象不能赋值给子类对象呢?这个和本博客的第一大点也有关系,因为可以把子类对象强制转换成父类类型,而这个代价就是,只能访问子类从父类继承的东西,即子类对象会退化成父类对象。换句话说,就是子类对象的大空间中包含的小空间(存放着从父类继承的成员变量)供你强制转换后使用。
而父类对象不能被强制转换成子类类型,所以自然也不能将父类对象赋值给子类对象,也不能通过父类对象对子类对象进行初始化,或者拷贝构造。因为这些函数都有this指针,要通过的第一关就是必须得允许this指针指向你,也就是将你强制转换成等号左边的类型。第一关就通不过,所以肯定不能这样操作。

父类指针指向子类对象的问题、父类对象和子类对象之间的问题相关推荐

  1. 父类指针指向子类对象,子类指针不能指向父类对象

    class Parent { public:int a };class Child :public Parent { public:int b; }Parent类占内存大小范围:int a; 占4个字 ...

  2. 父类指针指向子类实例,用父类指针调用虚函数,调用的是子类的函数还是父类的函数...

    父类指针指向子类实例,用父类指针调用虚函数,调用的是子类的函数还是父类的函数 以下程序的显示结果是什么,为什么 #include <iostream> using namespace st ...

  3. 父类指针可以指向子类对象

    结论:父类指针可以指向子类对象,但是只能访问父类成员,不能访问子类成员 结论:子类指针不可以指向父类对象,需要类型转换才可以 笔记: <1>.当基类指针指向派生类的时候,只能操作派生类从基 ...

  4. 多态---父指针指向子类对象(父类引用指向子类对象)

    我们都知道,面向对象程序设计中的类有三大特性:继承,封装,多态,这个也是介绍类的时候,必须提到的话题,那么今天就来看一下OC中类的三大特性: 一.封装 封装就是对类中的一些字段,方法进行保护,不被外界 ...

  5. Java多态 父类引用指向子类对象

    原文地址http://www.cnblogs.com/111testing/p/6880831.html Java多态的三个必要条件: 1. 继承 2. 子类重写父类方法 3. 父类引用指向子类对象 ...

  6. 父类引用指向子类对象详解

    父类引用指向子类对象 父类引用指向子类对象指的是: 例如父类Animal,子类Cat,Dog.其中Animal可以是类也可以是接口,Cat和Dog是继承或实现Animal的子类. Animal ani ...

  7. java子类引用指向父类对象_Java多态 父类引用指向子类对象

    Java多态的三个必要条件: 1. 继承 2. 子类重写父类方法 3. 父类引用指向子类对象 然后看一个例子 输出结果为: 给出结论:Father  c  =  new  Child()    在c的 ...

  8. 父类引用指向子类对象

    父类引用指向子类对象,如何访问子类的属性? 1.第一种办法最简单,强制类型转化为子类. 2.父类引用指向子类对象,由于当前引用为父类,只能访问父类的字段和方法,但是根据多态性可以访问子类的方法,在这个 ...

  9. Java多态-如何理解父类引用指向子类对象

    java多态,如何理解父类引用指向子类对象 要理解多态性,首先要知道什么是"向上转型". 我定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类.我可以通过   C ...

最新文章

  1. swiper 定义放多少张图片_swiper轮播问题之二:默认显示3张图片,中间显示全部两边显示部分...
  2. xamarin拖一个gridview控件报错怎么解决_[笔记阁]Xamarin初探:版式面板(一)
  3. oracle display set,Check if the DISPLAY variable is set
  4. jquery-本地存储-cookie插件
  5. 实时计算轻松上手,阿里云DataWorks Stream Studio正式发布
  6. 基础层区块链Harmony发布主网新版本v4.0.0
  7. ORACLE中将一个值赋值到另一个表的值
  8. Python实现简易的图书借阅管理系统
  9. 树莓派 —— 树莓派安装字体
  10. 关于Windows下使用CuteFTP向Ubuntu传文件时提示“请求被拒绝”
  11. 手机测试内存速度的软件,如何查看手机内存速度?手机内存读取速度测试_手机内存速度多少算正常...
  12. elasticsearch之analysis
  13. 10分钟教会你,如何用模拟量调试电机
  14. 点成分享 | 麦氏比浊仪在药敏试验中的应用
  15. beats 耳机 android,Beats app安卓,Beats app安卓耳机管理预约 v2.3.5 - 游戏盒子下载站...
  16. python多线程返回值问题重写Thread类的run方法
  17. 亚马逊账户违规了?如何自查
  18. MDC 实现 traceId 记录
  19. jdk9安装及java环境配置
  20. gardner环 matlab,HighSpeedLogic专题:位同步Gardner环的研究

热门文章

  1. 优先级翻转与优先级继承
  2. vim中进行复制粘贴
  3. 【Redis】查看redis服务的版本
  4. 吃糖果游戏(tyvj 1567)
  5. python—生产者消费者模型
  6. 二十、哈希表的基础知识
  7. 大学计算机制作九九乘法表,用Excel制作九九乘法表(一)
  8. 电机驱动电路之H桥基本知识---Trinamic电机驱动芯片
  9. 数据库查询之条件排序
  10. 关于显式类型转换以及隐式类型转换