ruby中的实例变量和类变量

 

 

为了解决老贾提出的,弄清楚为何继承的子类继承了类变量而没有继承实例变量的原因,需要弄清楚实例变量和类变量的存取方式。下面是我简单的一些分析,希望大家多多斧正。

 

 

*   类和对象的存储方式


对象的结构在 mateclass 的讲解中有了简单的介绍,下面是对象的结构体的示意图 1-1

 

 

1-1 ruby 对象的结构体

每个结构体上面都是有 Struct RBasic 结构,定义如下图 1-2

 

 

1-2 Struct RBasic 结构体

接着看下类的结构,定义如图 1-3 所示

 

1-3 RClass 的结构体

其中 iv_tbl 为实例变量表, m_tbl 为方法表, super 指向父类的指针

*   实例变量的设置与获取

下面是存储实例变量的代码图 1-4 ,主要看红色的部分。如果对象的类型是 Object Class Module ,如果实例变量表不存在,则创建,否则将变量的 ID Value 插入到实例变量表中。         

 

1-4 实例变量的存储方式

         接下来看下实例变量是如何获取的如图 1-5 。注意我下面标注红色的部分,此处, 如果对象的类型是 Object Class Module ,则搜索实例变量表中的实例变量,找到返回,终止 switch 。未找到返回 nil

        

1-5 实例变量的获取方式

当然这里的实例变量表,如果是struct RClass ,那么就代表这 是一个类对象,这个实例变量表是用于类对象本身。

*   下面我们分析为何下面的代码无法获得预期效果

        

 

实例变量在执行 new 后,生成了一个新的对象,我们暂且叫它 obj ,这里 obj 其实本身有自己的实例变量 @a ,当我们调用 obj.a 方法的时候, obj 首先找他的类里的方法 a a 返回的是实例变量,这里的实例变量其实是 obj 本身的实例变量,如图 1-6 所示。

 

 

1-6 类与对象的实例变量

因此,对于上面的代码执行 @a = abc ”操作后,其实 Struct RClass 中实现了 @a = abc ”并没有改变 Struct Robject 实例变量。所以通过 a 方法调用的值会为 nil

所以下面的代码也就很好分析出了  

    

 


输出结构是 abc ,因为调用自身的实例变量。

下一个问题,为什么采用了 Initialize 后就可以实现初始化呢,我的理解是这样子的,首先类调用 new ,在 new 里做了什么动作呢,依据面向对象的经验,估计是先做了一些内存分配的任务,内存分配完成实际上对象已经存在了,接着调用 Initialize ,此时的该方法应该是在类中,查找类的 Initialize 方法,初始化本身的实例变量。所以可以实现对实例变量的初始化。

 

*   类变量的存储方式

看下面的代码图1-7 是获取类变量的函数,同样注意红色的部分while 一重循环,下面查找RClass 结构中的iv_tbl ,如果找到返回找到的值,未找到则有 tmp = CLASS(tmp)->super ,指向父类继续寻找。 因为创建 ID 时,考虑的是变量的全名,包括前缀: rb_intern() @var @@var 返回的是不同的 ID ,因此不可能把@var 当成了类变量的情况。

细心的你,一定会发现,类变量存储在了类的实例变量表里,其实正是如此。

 

1-7 类变量的获取函数

 

 

至此,我们已经知道了为何下面的类变量是可以继承,而实例变量无法继承了,因为实例变量没有回溯父类查找( tmp = CLASS(tmp)->super ),只是查找了对象或类对象本身。

因此解释了老贾的第二个问题。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值