如果类方法被覆盖,则访问类

lul*_*ala 4 ruby

这是一个外部类,其class方法已被覆盖。

class Foo
  def class
    "fooo"
  end
end

class Boo < Foo
end

class Moo < Foo
end
Run Code Online (Sandbox Code Playgroud)

现在,我有一个子类的实例。是否可以找出它属于哪个类?

foo.class # currently returns 'fooo', I want get Boo or Moo.
Run Code Online (Sandbox Code Playgroud)

mu *_*ort 8

您可以用来从安全的地方(例如)instance_method获取class方法,将未绑定的方法绑定到您的实例,然后调用它。例如:ObjectUnboundMethod

class_method = Object.instance_method(:class)
# #<UnboundMethod: Object(Kernel)#class> 

class_method.bind(Boo.new).call
# Boo 

class_method.bind(Moo.new).call
# Moo 

class_method.bind(Foo.new).call
# Foo 
Run Code Online (Sandbox Code Playgroud)

当然,如果您也替换了Object#class(或Kernel#class),那么所有的赌注都消失了,您将面临一个全新的痛苦与困惑世界。


Car*_*and 5

我更喜欢@Stefan和@muistooshort的解决方案,但这是替代方案。

class Foo
  def class
    "foo"
  end
end

class Boo < Foo
end

class Who < Boo
  def class
    "who"
  end
end
Run Code Online (Sandbox Code Playgroud)

boo = Boo.new
boo.method(:class).super_method.call
  #=> Boo

who = Who.new
who.method(:class).super_method.call
  #=> "foo"
who.method(:class).super_method.super_method.call
  #=> Who
Run Code Online (Sandbox Code Playgroud)

更普遍:

def my_class(obj)
  m = obj.method(:class)
  until m.owner == Kernel do
    m = m.super_method
  end
  m.call
end

my_class(boo)
  #=> Boo 
my_class(who)
  #=> Who
Run Code Online (Sandbox Code Playgroud)

参见Method#super_method


Ste*_*fan 5

对象的类也恰好是superclass其的类singleton_class

Boo.new.singleton_class.superclass
#=> Boo

Moo.new.singleton_class.superclass
#=> Moo

Foo.new.singleton_class.superclass
#=> Boo
Run Code Online (Sandbox Code Playgroud)

  • 您也可以使用`class &lt;&lt; Boo.new; 超类; 如果担心担心可能会覆盖“ singleton_class”。 (2认同)