西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页编程开发其它知识 → 关于OO中继承的思考-深度认识类,对象,内存分配

关于OO中继承的思考-深度认识类,对象,内存分配

相关软件相关文章发表评论 来源:本站整理时间:2010/10/18 14:29:46字体大小:A-A+

作者:佚名点击:84次评论:0次标签: 继承 内存分配 对象

ios星骸继承者破解版v1.17.3 iPhone/iPad版
  • 类型:ios角色扮演大小:62.8M语言:中文 评分:10.0
  • 标签:
立即下载
曾经在一本书中看到过这样的一个问题:(语言:C++)

如果两个类,Parent和Child,Child继承Parent,Parent有一个函数print(),有成员变量pVar,Child中有两个函数print(),privatePrint(),有成员变量cVar,

现在 ,申明一个Parent类型的指针来指向一个Child的对象。

那么用这个指针可以调用privatePrint()函数吗?可以用这个指针可以调用成员cVar吗?

答案是:不能。

那如果Parent中有一个虚函数privatePrint(),那么可以调用到privatePrint()吗?

答案是:可以。

首先我用C++试了一遍。C++的代码如下
代码
1 #include <iostream>
2
3 using namespace std;
4
5 class Prarent
6 {
7 public:
8 Prarent(){};
9 int pVar;
10 void print()
11 {
12 cout<<"I am parent"<< endl;
13 }
14 //virtual void privatePrint(){};
15 };
16
17 class Child : public Prarent
18 {
19 public:
20 Child(){};
21 int cVar;
22 void print()
23 {
24 cout<<"I am child"<< endl;
25 }
26 void privatePrint()
27 {
28 cout<<"I am child' function privatePrint()"<< endl;
29 }
30 };
31
32 void main()
33 {
34 Prarent *parent;
35 Child child; // 原先我竟然写成 Child child = new Child(); 用久了C#, 都是C#惹的祸.
36 parent = &child;
37 parent->print();
38 // parent->privatePrint(); 编译通不过.
39 // 1: 说明父类的指针虽然指向了子类的对象, 但是却不能引用父类没有申明的函数.
40 // 2: 但是你将privatePrint申明为父类的虚函数, 则上面的可以运行成功.
41 }
42
43

其实之前我没有怎么在意这个问题。知道My sen Brother问了我。我才发现问题并非简单。

经过了我们相互的讨论之后,我们得到了一种解释。

我不敢保证一定完全是对的。但是却是我们自己的心得和体会。


理解这个问题。首先要明白两个问题:1:类在内存是怎么存放的?(编译阶段实现)2:对象实例在内存中是怎么存放的?

1:类在内存是怎么存放的?

我根据以前Teacher Lei说过的一些内容,计算机组成,汇编语言,自己看过一些书,得到自己的一种思考。

其中一个类,通过编译分别存在内存的两块地方,一个是代码段,一个是数据段;

代码段存放一个类的成员变量;(ie. 上面的pVar和cVar都是存放在代码段中)

数据段存放一个类的成员函数表;(ie. 上面的print()和privatePrint()都存放于这里);

数据段中的每一个类的内存块应该由两个表填充,一个为虚函数表,一个为非虚函数表;

数据段中类的成员变量存放,如下:

int pVar

int cVar


代码段中类的成员函数表存放,如下:
Parent()

Print()

Child()

Print()

pravtePrint()


下面来解释 2:对象实例在内存中是怎么存放的?

我们拿上面的例子来说明:

当初始化一个Parent *parent 一个指针对象时,这时候parent所指向的地址就是100;


vPtr(虚函数指针) 地址:100

int pVar

当初始化一个Child类型 child 对象时,这时候child的地址就是200;(注意和指针不一样)

vPtr(虚函数指针) 地址:200

int pVar

int cVar


首先:为什么这边一定是这样排列的

还记得Teacher Lei说过吗?原因:子类在初始化的时候是先调用父类的构造函数!!

说明父类的成员一定是先被初始化的。

所以这边的结构必然是这样的。(这里很重要)

好了。到现在基本就把要知道的基础知识解决了。

不知道读着博客的人累了没有。。呵呵。后面的更精彩。



现在 把child对象的地址赋值给指针parent(即 parent = &child)

先来看看 parent->cVar 为什么不行?!

第一步:parent->cVar 其实是一个地址的偏移过程,现在parent的地址是200;那么cVar就代表2个偏移量;

按说电脑是可以找到202的这个地址的值。可是为什么不行呢?

第二步:在程序的编译过程中,每一个的成员函数名都被当做一个偏移量。

就像这里,pVar代表量1个偏移。cVar代表2个偏移量。

第三步:parent是Parent类型的。这个很关键。因为在编译的以后,parent已经初始化了一个最大偏移量max (这里的max为1)

第四步:结果已经很明显了。因为parent的最大偏移量max 为1。程序根本找不着偏移量为2的变量地址。


然后看看 parent->privatePrint() 为什么不行?
还是那个关键点。parent是Parent类型的,还记得上面说类在内存中的加载方式吗?parent指向的是Parent的内存块。所以在那个内存块中,根本找不着privatePrint()这个函数。

可是?有人因为会问了?为什么如果在Parent中申明了一个虚函数类型的privatePrint()就可以了呢?

还记得类的实例在内存中加载的那个图吗?每个类的前面都有一个的vPtr虚函数指针,他指向的是当前类的虚函数表。通过虚函数表中的privatePrint()也相当一个指针,指向了子类中实现父类虚函数的privatePrint(),自然就能找到了。

此时一切真相大白!!
    星骸继承者
    (9)星骸继承者
    星骸继承者西西专区为您提供该游戏的破解版电脑版苹果版辅助修改器等相关下载助你在游戏中能够玩的更加的愉快快来下载游戏体验吧星骸继承者简介星骸继承者是款以星际逃亡为背景,与异星生物协同作战,反抗侵蚀宇宙的恐怖黑暗生命体的科幻向手游。每个人都有一个星际梦,不管是对异星的向往还是对未知的探索在科技日益发达的未来世界,人类已经能够成功的在宇宙中发展殖民行星。然而,宇宙中强大的黑暗生物迷之生命体塔拉劫多袭击了...更多>>
    • 星骸继承者官网v1.0 安卓版

      10-13 / 55.1M

      推荐理由:星骸继承者是一款日系奇幻风格的扮演类手机游戏,近未来科幻背景题材,为了生存抵御外星人,任务玩法多样精
    • 星骸继承者内购破解版v1.0 安卓版

      10-13 / 55.1M

      推荐理由:星骸继承者破解版是一款神秘的魔幻风扮演类RPG游戏,全3D超清画质打造,超酷炫多视角旋转镜头捕捉技术,拳拳
    • 星骸继承者电脑版v1.0

      10-13 / 55.1M

      推荐理由:星骸继承者电脑版是一款精美的日系RPG扮演类手机游戏,高清细腻的视网膜画面技术,带来极致精美的Q
    • ios星骸继承者破解版v1.17.3 iPhon

      10-13 / 62.8M

      推荐理由:ios星骸继承者破解版是一款史诗级的科幻手游大作,宏大的历史背景世界观,超高清的星际逼真场景,视觉听觉双
    • 烧饼游戏修改器V3.1 最新版

      01-29 / 970KB

      推荐理由:《烧饼游戏修改器SBgametool》是迄今为止Android平台上最简单好用的游戏修改工具(没有之一),精小,快速,绿
    • 叉叉助手2.5.1 官方安卓版

      12-14 / 24.5M

      推荐理由:叉叉助手辅助凭着天天酷跑游戏赢得了好多的用户,现在叉叉助手升级管理辅助,之前单个游戏叉叉助手历史版本

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)