Ruby - 如何处理子类意外覆盖超类私有字段的问题?

时间:2011-03-18 13:52:22

标签: ruby oop subclass subclassing

假设您编写了一个类Sup,我决定将其扩展为Sub< Sup。我不仅需要了解您发布的界面,还需要了解您的私人领域。见证这次失败:

class Sup

  def initialize
    @privateField = "from sup"
  end

  def getX
    return @privateField
  end
end

class Sub < Sup

  def initialize
    super()
    @privateField = "i really hope Sup does not use this field"
  end
end

obj = Sub.new
print obj.getX #  prints "i really hope Sup does not use this field"

问题是,解决这个问题的正确方法是什么?似乎子类应该能够使用它想要的任何字段而不会弄乱超类。

编辑:equivalent example in Java返回"from Sup",这也是应该产生的答案。

4 个答案:

答案 0 :(得分:9)

实例变量与继承无关,它们是在第一次使用时创建的,而不是通过某种定义机制创建的,因此在语言中没有对它们进行特殊的访问控制,并且它们不能被遮蔽。

  

我不仅要了解你的意思   发布的界面,但我也需要   了解你的私人领域。

实际上这是一个“官方”的立场。摘自“Ruby编程语言”一书(Matz是其中一位作者):

  

......这是为什么扩展Ruby只是安全的另一个原因   你熟悉的课程   (并控制)实施   超类。

如果你不知道它内外都是你自己的。悲伤却又是真的。

答案 1 :(得分:1)

不要继承它!

使用合成而不是继承。

编辑:而不是MyObject子类化ExistingObject,看看my_object是否有一个引用existing_object的实例变量更合适。

实例变量属于实例(即对象)。他们不是由班级自己决定的。

答案 2 :(得分:1)

与java / C#不同,在ruby中,私有变量始终对继承类可见。无法隐藏私有变量。

答案 3 :(得分:-1)

Ruby和Java不会以同样的方式对待'私有'属性。在Ruby中,如果你将某些东西标记为私有,那只意味着它不能用接收者调用,即:

 class Sub
   private
   def foo; end
 end

sub.foo => error accessing private method with caller

但是如果你改变自己是谁,你总是可以访问它:

sub.instance_eval { foo } #instance_eval changes self to receiver, 'sub' in this example

结论:不要依赖你可以隐藏或保护外太空的东西!或者以强大的力量来承担巨大的责任!

编辑:

是的,我知道问题是针对字段的,但这是一回事。你可以随时做:

sub.instance_eval { @my_private_field = 'something else' }
puts sub.instance_eval { @my_private_field }