天天看點

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