您的位置:首页 > 编程语言 > Ruby

ruby中的实例变量和类变量

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



类和对象的存储方式


对象的结构在
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

,那么就代表这

是一个类对象,这个实例变量表是用于类对象本身。



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

class YourClass
@a = 'abc'
def a
@a
end
end
p YourClass.new.a


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

a
返回的是实例变量,这里的实例变量其实是
obj
本身的实例变量,如图
1-6
所示。




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

因此,对于上面的代码执行
@a =

abc
”操作后,其实
Struct RClass
中实现了
@a =

abc
”并没有改变
Struct Robject
实例变量。所以通过
a
方法调用的值会为
nil


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

class YourClass2
@a = 'abc'
def self.a
@a
end
end


输出结构是
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

),只是查找了对象或类对象本身。

因此解释了老贾的第二个问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: