天天看点

Ruby的对象模型

  ruby的对象模型,包含在下面这张图中:

Ruby的对象模型

    首先要知道,ruby中的类也是对象,类相比于其他对象特殊的地方在于能够产生对象,既然类是对象,那么它显然也有类,也就是所谓类的类,这个类的类在ruby中就是类的metaclass,图中的(otherclass),(otherclass)就是类otherclass的klass(c层次),(otherclass)存储了类的方法(类方法)和类的实例变量,并且是唯一的且不可实例化。在ruby层次上我们想操作(otherclass)应该类似:

class otherclass

end

class<<otherclass

  attr_accessor:name #name是otherclass的实例变量

  def test

    p 'hello'

  end

otherclass.name='1'

p otherclass.name

otherclass.test

    图中的instance是otherclass的一个实例,那么显然instance的class是otherclass,可是图中的(instance)又是什么呢?(instance)就是对象的singleton类,singleton类这个名称怪怪的,不过每个对象只能有一个singleton类的角度上说也可以理解。看看下面的例子:

instance=otherclass.new

class<<instance

    p "a.test"

  attr_accessor:name

instance.test

instance.name="dennis"

p instance.name

     instance通过otherclass.new创建,但是此时(instance)还不存在,这与(otherclass)情况不同,每个类一经创建就有一个metaclass,而对象就不一样,只有当你通过class<<instance 语法创建的时候,(instance)才被创建。注意test方法和name变量都将是instance对象特有的,类otherclass并没有改变。观察下,发现(instance)继承于otherclass,引出类的metaclass与对象的singleton类的又一个区别:类的metaclass继承自父类的metaclass,而对象的singleton类则是继承于对象的class。

    那么当我们调用instance.class的时候,怎么不返回(instance)?这是c ruby在底层做了处理,instance的class在c ruby层次是(instance),当查找的时候忽略了singleton类以及下面将要谈到的include模块的代理类,沿着继承链上查找:

86 value

87 rb_obj_class(obj)

88 value obj;

89 {

90 return rb_class_real(class_of(obj));

91 }

76 value

77 rb_class_real(cl)

78 value cl;

79 {

80 while (fl_test(cl, fl_singleton) || type(cl) == t_iclass) {

81 cl = rclass(cl)->super;

82 }

83 return cl;

84 }

(object.c)

核心代码就是:

while (fl_test(cl, fl_singleton) || type(cl) == t_iclass) {

  cl = rclass(cl)->super;

 }

    其中fl_test(cl,fl_singleton)用于测试是否是singleton类,而type(cl)==tl_iclass是否是包含模块的代理类,tl_iclass的i就是include的意思。

    图中类otherclass继承object,这个是显而易见的,不再多说。而object、class和module这三个类是没办法通过api创建的,称为元类,他们的之间的关系如图所示,object的class是class,module继承object,而class又继承module,因此class.kind_of? object返回true,这个问题类似先有鸡,还是先有蛋的问题,是先有object?还是先有class?而c ruby的解决办法是不管谁先有,创建object开始,接着创建module和class,然后分别创建它们的metaclass,从此整个ruby的对象模型开始运转。

1243 rb_cobject = boot_defclass("object", 0);

1244 rb_cmodule = boot_defclass("module", rb_cobject);

1245 rb_cclass = boot_defclass("class", rb_cmodule);

1246

1247 metaclass = rb_make_metaclass(rb_cobject, rb_cclass);

1248 metaclass = rb_make_metaclass(rb_cmodule, metaclass);

1249 metaclass = rb_make_metaclass(rb_cclass, metaclass);

那么当我们调用class.class发生了什么?class的klass其实指向的是(class),可根据上面的代码,我们知道会忽略这个(class),继续往上找就是(module),同理找到(object),而(object)继承自class,显然class的类仍然是class,class的类的类也是class,多么有趣。同理,object.class和module.class都将是class类。

    再来看看include模块时发生的故事。include模块的过程如下图所示:

Ruby的对象模型

include模块,本质上是在对象或者类的klass和super之间插入了一个代理类iclass,这个代理类的方法表(m_table)和变量表(iv_table)分别指向了被包含的模块的方法表和变量表(通过指针,因此当包含的module变化的时候,对象或者类也能相应变化),那么在查找类或者对象的class的时候,上面已经说明将忽略这些代理类。

文章转自庄周梦蝶  ,原文发布时间2007-09-29