-
2006-10-30
管窥Ruby——类层次结构
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://dreamhead.blogbus.com/logs/3730547.html
关于一个RClass结构,我已经写了几篇blog来讨论其中的内容,没办法,谁让Ruby是一种面向对象的程序设计语言呢!类是核心的概念之一,而且很多看似魔术的东西,就是靠这些基础的东西支撑起来的。前面的讨论,我们已经见识过方法和变量了,这里就来看一下RClass中的另外一个字段:super。
回忆一下面向对象的特点:封装、继承、多态。super的出现为继承打下了基础,而多态是要靠继承来发挥作用的,所以,super这样一个字段将原本孤立的类联系到了一起,一个庞大的体系得以运转起来。
从这里的定义,我们便不难发现,Ruby是一个单一继承的体系,因为它只能有一个super。
在Ruby中,super并不像看起来那么简单,因为在实际的处理中,有些功能就是通过这个字段做一些手脚来支持的。下面就来看看以包含模块是如何实现的。
前面的讨论已经提到了,Ruby是一个单一继承的体系,通过mixin,它可以达到类似于多重继承的功能,而mixin实际上就是包含了一个模块。下面这段代码便展示了如何实现一个类包含一个模块的方法:
void
rb_include_module(klass, module)
VALUE klass, module;
{
VALUE p, c;
int changed = 0;rb_frozen_class_p(klass);
if (!OBJ_TAINTED(klass)) {
rb_secure(4);
}
if (NIL_P(module)) return;
if (klass == module) return;if (TYPE(module) != T_MODULE) {
Check_Type(module, T_MODULE);
}OBJ_INFECT(klass, module);
c = klass;
while (module) {
int superclass_seen = Qfalse;if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl)
rb_raise(rb_eArgError, "cyclic include detected");
/* ignore if the module included already in superclasses */
for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
switch (BUILTIN_TYPE(p)) {
case T_ICLASS:
if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
if (!superclass_seen) {
c = p; /* move insertion point */
}
goto skip;
}
break;
case T_CLASS:
superclass_seen = Qtrue;
break;
}
}
c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
changed = 1;
skip:
module = RCLASS(module)->super;
}
if (changed) rb_clear_cache();
}
(class.c)前面部分的代码大多用于检查,比如参数是否合法,防止重复包含等等,简化一下,这段代码主要就是一句话:
c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);创建一个类,把用来包含模块类的super指向它,我们也看到了在创建这个类的函数使用了原有的super作为参数,不难猜测,通过这样一个语句,我们便把一个创建出来的新类插入到现有的类层次结构之中。下面便是这个函数的实现:
static VALUE
include_class_new(module, super)
VALUE module, super;
{
NEWOBJ(klass, struct RClass);
OBJSETUP(klass, rb_cClass, T_ICLASS);if (BUILTIN_TYPE(module) == T_ICLASS) {
module = RBASIC(module)->klass;
}
if (!RCLASS(module)->iv_tbl) {
RCLASS(module)->iv_tbl = st_init_numtable();
}
klass->iv_tbl = RCLASS(module)->iv_tbl;
klass->m_tbl = RCLASS(module)->m_tbl;
klass->super = super;
if (TYPE(module) == T_ICLASS) {
RBASIC(klass)->klass = RBASIC(module)->klass;
}
else {
RBASIC(klass)->klass = module;
}
OBJ_INFECT(klass, module);
OBJ_INFECT(klass, super);return (VALUE)klass;
}
(class.c)这段代码主要完成了一些赋值,包括我们前面所说的,将类连接到类层次结构中。稍微需要提一下的是,这里对iv_tbl和m_tbl采用了直接赋值,而这两个字段都是指针,这样的赋值方式让两个不同的对象指向了同一个表,也就是说,如果module新增了方法,class同样可以拥有。
或许,我们会有疑问,这样的实现修改了类的继承关系,岂不会有很大的影响。这完全不必担心。我们看到,在这里给这个新类附的类型是T_ICLASS,而不是通常类说具有的T_CLASS。在Ruby的类层次结构中,存在一些“实际中不存在”的类,这里的包含类就是其中一种,这些类在Ruby的层次上根本看不见。当我们需要找一个类的超类时,这些类会被跳过。把它们放到类的层次结构中,查找方法时,我们不必做特殊的处理。
引用地址:
模块中的类方法
Blog:梦想风暴2008-09-02 09:10:43










评论