【问题标题】:How does Inheritance work in Ruby?继承在 Ruby 中是如何工作的?
【发布时间】:2012-12-18 16:28:30
【问题描述】:

根据his talk about the Ruby Object Model 中的 Dave Thomas 所说,Ruby 中没有“类方法”。只是方法的接收者是“类对象”还是“实例对象”的区别。

class Dave
  def InstaceMethod              ### will be stored in the current class (Dave)
    puts "Hi"
  end
  class << self                  ### Creates an eigenclass, if not created before
    def say_hello
      puts "Hello"
    end
  end
end

默认情况下,ancestors 方法不显示元类:

class Dave
  class << self
    def metaclass                ### A way to show the hidden eigenclass
      class << self; self; end
    end
  end
end

p Dave.ancestors
# => [Dave, Object, Kernel, BasicObject]
p Dave.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]

但是,我认为真正的应该是这样的:

# => [<eigenclass>, Class, Module, Object, Kernel, BasicObject]

p Dave.class.instance_method(false)
# => [:allocate, :new, :superclass]
p Dave.metaclass.instance_method(false)
# => [:say_hello, :metaclass]

现在是继承。

class B < Dave
end

p B.say_hello
# => "Hello"
p B.ancestors
# => [B, Dave, Object, Kernel, BasicObject]
p B.class.instance_methods(false)
# => [:allocate, :new, :superclass]

以下将为B 创建一个新的特征类:

p B.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
p B.metaclass.instance_method(false)
# => []
  1. 如果还包含特征类,B.ancestorsB.metaclass.ancestors 会是什么样子?方法say_hello 存储在一个特征类中(我假设B.class 继承自),但它在哪里?

  2. 既然有两个祖先链(B.ancestorsB.class.ancestorsB.metaclass.ancestors),那么继承实际上是如何发生的?

【问题讨论】:

    标签: ruby oop inheritance metaclass eigenclass


    【解决方案1】:

    一个对象(以及作为对象的类,Class 的实例)有一个指向其类的类字段。创建一个单例类(eigenclass/metaclass)会创建一个匿名类并将这个指针更改为指向匿名类,其类指针将指向原始类。 class 方法不显示匿名类,只显示原始类。对于 mixins 也是一样。一个类有一个超类字段。方法include 创建一个匿名代理,超类指针更改为指向匿名代理类,并从那里指向超类。方法ancestors 不显示匿名类,而是显示包含模块的名称。 superclass 方法不显示匿名代理类,只显示原始超类。

    您可以阅读:Why are symbols in Ruby not thought of as a type of variable?

    在对此答案的评论中,有一个关于单例类的有趣文章的链接,可以在 Devalot 博客上找到。

    需要一些时间来吸收这些继承链。一张好图值得长篇大论,我推荐The Pickaxe的第24章元编程,里面有关于所有这些链的各种图片。

    默认情况下,祖先方法不显示元类:
    和 1. 当特征类也包括在内时,B.ancestors ... 会是什么样子?

    ancestors 关注超类链。本征类不属于超类链。

    p Dave.metaclass.ancestors
    => [类、模块、对象、内核、基本对象]
    但是,我认为真正的应该是这样的:
    => [“eigenclass”,类,模块,对象,内核,BasicObject]

    正确。

    您可以简化您的 Dave 课程:

    class Dave
        def self.say_hello    # another way to create an eigenclass, if not created before
          puts "Hello"
        end
        def self.metaclass    # A way to show the hidden eigenclass
            class << self
                self
            end
        end
    end
    
    Dave.say_hello           # => Hello
    Dave.new.class.say_hello # => Hello
    p Dave.metaclass.instance_methods(false) # => [:say_hello, :metaclass]
    p Dave.singleton_methods                 # => [:say_hello, :metaclass]
    

    def self.metaclass 从 Ruby 1.9.2 开始就多余了,它引入了Object#singleton_class

    【讨论】:

      【解决方案2】:

      Eigenclass 是一个鬼鬼祟祟的隐藏类。你已经通过开课成功地揭示了它。但它并不存在于普通阶级的祖先中。而且由于它是隐藏的,因此您无法通过将ancestors 方法发送到特征类本身来查看它。继承树如下:

      B ---S-->  Dave   ---S---> Object  ---S---> BasicObject
      |            |               |                  |
      E            E               E                  E
      |            |               |                  |
      #B --S--> #Dave   ---S---> #Object ---S---> #BasicObject --S---> Class,,Object,BasicObject
      

      S 代表超类,E 代表本征类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多