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
end
OtherClass.name='1'
p OtherClass.name
OtherClass.test
图中的instance是OtherClass的一个实例,那么显然instance的class是OtherClass,可是图中的(instance)又是什么呢?(instance)就是对象的singleton类,singleton类这个名称怪怪的,不过每个对象只能有一个singleton类的角度上说也可以理解。看看下面的例子:
class OtherClass
end
instance=OtherClass.new
class<<instance
def test
p "a.test"
end
attr_accessor:name
end
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);
(object.c)
那么当我们调用Class.class发生了什么?Class的klass其实指向的是(Class),可根据上面的代码,我们知道会忽略这个(Class),继续往上找就是(Module),同理找到(Object),而(Object)继承自Class,显然Class的类仍然是Class,Class的类的类也是Class,多么有趣。同理,Object.class和Module.class都将是Class类。
再来看看include模块时发生的故事。include模块的过程如下图所示:
include模块,本质上是在对象或者类的klass和super之间插入了一个代理类iclass,这个代理类的方法表(m_table)和变量表(iv_table)分别指向了被包含的模块的方法表和变量表(通过指针,因此当包含的Module变化的时候,对象或者类也能相应变化),那么在查找类或者对象的class的时候,上面已经说明将忽略这些代理类。
文章转自庄周梦蝶 ,原文发布时间2007-09-29