关于覆盖初始化方法的问题

时间:2009-11-30 08:27:08

标签: ruby

我遇到了一个关于覆盖BigDecimal初始化消息的奇怪问题。

class Test1 < String
  def initialize(a, b)
    puts a
    puts b
  end
end

require 'bigdecimal'
class Test2 < BigDecimal
  def initialize(a, b)
    puts a
    puts b
  end
end

>> Test1.new('a', 'b')
a
b
>> Test2.new('a', 'b')
TypeError: wrong argument type String (expected Fixnum)
    from (irb):17:in `new'
    from (irb):17

为什么我可以覆盖String的初始化消息,但不能覆盖BigDecimal?

3 个答案:

答案 0 :(得分:2)

当您查看Ruby类的来源时,您会看到String类定义方法String#initialize,该方法在String#new之后调用(继承自Object)用于分配新实例。您不要在新实例中调用String#initialize(或#super),以便在检查新创建的对象时获得""

BigDecimal定义方法Bigdecimal#new,它分配自己的对象。对象创建由两部分组成 - 为新对象分配空间并初始化它。您只定义了初始化新对象,因此您可以使用默认的对象分配空间。如果您要覆盖它,则应在新课程中定义#new,并使用适当的参数调用BigDecimal的{​​{1}}。

希望能澄清你的例子中发生的事情。

答案 1 :(得分:2)

是的,BigDecimal实现了新的类方法,如果你在test2类中覆盖它,那么你可以用任何你想要的方式编写Test2初始化方法,例如。

class Test2 < BigDecimal
  def self.new(a)
    puts a
  end

  def initialize(a)
    puts a
  end
end

Test2.new("a")

类方法new是对象构造函数,它使用initialize方法设置对象状态并在初始化对象后分配内存。

但是通常我们不实现新方法,因为它是ruby提供的默认构造方法,尽管如果有充分的理由可以通过在类中重新定义它来覆盖它,那就是BigDecimal所做的。

答案 2 :(得分:1)

看起来BigDecimal.new()中发生了一些类型检查,在达到被覆盖的initialize之前就会感到沮丧。见this list

中的第19点

这通常不是一个问题(我记得一些东西,但仍然要查找它)但是有一个new类方法,如果我没记错的话,实际创建了对象,然后调用initialize

覆盖课堂上的new,因此:

class Test2 < BigDecimal
  def Test2.new(a, b)
    puts a
    puts b
  end
end

Test2.new('42', 'banana')

给出了希望的答案。