6

在 Ruby 中,我们可以使用superinside 单例方法来调用相应超类的单例方法,如下面的代码所示。

class Base
  def self.class_method
    puts "Base class method"
  end
end

class Derived < Base
  def self.class_method
    puts "Derived class method"
    super
  end
end

Derived.class_method
# Derived class method
# Base class method

但是,我似乎不太明白对 inside 的调用是如何super到达Derived.class_methodBase.class_method。我假设这class_method是在他们的元类上定义的,这是否意味着他们的元类具有父/子关系?(我不能通过实验完全证实)

更新:我问这个问题是因为我记得在某处看到基类和派生类的元类之间存在某种关系(但我再也找不到它了)。除了了解实际super工作原理之外,我还想确认这两个元类是否完全分开。

4

3 回答 3

11

这里有四个类对象:

<Class>---class---><Class>
Base               #Base
   ^                  ^
   |                  |
   |                  |
 super              super
   |                  |
   |                  |
<Class>            <Class>
Derived---class--->#Derived

命名法:

  • <...> 是每个对象的类。
  • 类的名称在第二行。
  • 如果名称以 # 开头,则它是 eigenclass(又名单例类)。
  • super 指向一个类的超类
  • class 指向类的类。

当你调用 Derived.class_method 时,Ruby 遵循“先右后上”的规则:先去对象的类,然后顺着超类链上去,找到方法后停止:

  • “class_method”调用的接收者是派生的。因此,沿着链向右指向 Derived 的类对象,即其特征类 (#Derived)。
  • Derived 没有定义方法,因此 Ruby 沿着链向上到达#Derived 的超类,即#Base。

  • 该方法在此处找到,因此 Ruby 将消息分派到 #Base.class_method

你不会认为我对这些事情一无所知吧?这是我的大脑得到所有这些元juju的地方:元编程Ruby

第 2 部分。 如何让“eigenclass”(又名“singleton class”)摆脱隐藏

class Object
  def eigenclass
    class << self
      self
    end
  end
end

此方法将返回任何对象的特征类。现在,上课呢?那些也是对象。

p Derived.eigenclass               # => #<Class:Derived>
p Derived.eigenclass.superclass    # => #<Class:Base>
p Base.eigenclass                  # => #<Class:Base>

注意:以上来自Ruby1.9。在 Ruby 1.8 下运行时,您会得到一个惊喜:

p Derived.eigenclass.superclass    # => #<Class:Class>
于 2010-01-26T07:12:27.897 回答
4

为了澄清和纠正我在评论中关于 Ruby 隐藏/暴露特征类的方式所写的内容,情况如下:

红宝石 1.8:

(1) 该方法总是返回对象的实际Object#class类的第一个真正的(非 eigenclass 或 iclass)超类。例如

o = Object.new
class << o; end
o.class #=> returns Object, even though the _actual_ class is the eigenclass of o

换句话说,该Object#class方法永远不会返回一个特征类,它会越过它们,而是返回它在继承层次结构中找到的第一个“真实”类。

(2) 该Class#superclass方法有两种情况。如果接收者不是一个特征类,那么它只返回超类。然而,如果接收器一个特征类,那么这个方法返回接收器的实际(即不一定是真实的)类。

# case where receiver is a normal class (i.e not an eigenclass)
Module.superclass #=> Object (behaves as expected)

# case where receiver is an eigenclass
class << Module; superclass; end #=> returns Class, this is NOT the superclass

从上面看,Class#superclass在普通类的情况下表现如预期,但对于 eigenclass 示例,它声明 Module 的 eigenclass 的超类是 Class ,这是不正确的。从这张图http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/我们知道Module的eigenclass的超类实际上是Object的eigenclass。我不确定为什么 Ruby 1.8 会有这种奇怪的行为。

红宝石 1.9:

(1) 该Object#class方法的行为与 1.8 版本相同。

(2) 该Class#superclass方法不再有两种情况,它现在对待本征类的方式与对待普通类的方式相同,并按预期返回实际的超类。

例如

class << Module; superclass; end #=> #<Class:Object>
于 2010-01-26T13:02:34.363 回答
3

此图解释了关系:http ://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

此外,这里还有一些其他的帖子可以解释特征类的复杂性: http ://www.klankboomklang.com/2007/10/05/the-metaclass/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/

这是一个相当困难的解释,比你可能想知道的更多:http: //banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

于 2010-01-26T07:59:43.343 回答