• 2006-10-30

    管窥Ruby——类层次结构

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-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了,怎么现在到北京发展了吗?也不联系我,terryyu012@hotmail.com。