【问题标题】:Ruby - how to handle problem of subclass accidentally overriding superclass's private fields?Ruby - 如何处理子类意外覆盖超类私有字段的问题?
【发布时间】:2011-03-18 13:52:21
【问题描述】:

假设你写了一个类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",这也是应该产生的答案。

【问题讨论】:

  • 在这种情况下,您希望.getX 返回什么?你在调用 super 之后覆盖了这个字段,所以输出应该是你得到的那个。
  • @Dogbert:看看this example in Java。 “from Sup”是正确答案
  • 如果使用 privateField 而不是 @privateField,您将得到“来自 sup”的结果。
  • @krunal shah:似乎不起作用..你能发布一个答案并更明确吗?
  • 您也可以使用 __privateField 将其转换为 Python。 Python 将每个类中的 __privateField 重命名为 __Sub_privateField 和 __Sup_privateField。我不确定 Ruby 中是否有类似物。

标签: ruby oop subclass subclassing


【解决方案1】:

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

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

其实这是一个“官方”的立场。摘自“The Ruby Programming Language”一书(Matz 是作者之一):

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

如果你不知道里里外外,那你就只能靠自己了。悲伤但真实。

【讨论】:

    【解决方案2】:

    不要继承它!

    使用组合而不是继承。

    编辑:与其将 MyObject 子类化 ExistingObject,不如查看 my_object 是否具有引用 existing_object 的实例变量更合适。

    实例变量属于实例(即对象)。它们不是由类本身决定的。

    【讨论】:

    • 嗯有点避免这个问题。这是一个人为的例子,所以以不同的方式设计它无助于回答它=P。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      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 }
      

      【讨论】:

      • 这涉及方法,但我关心的是实例变量
      • 问题是关于实例变量,而不是方法。
      • 同样的事情,伙计。你可以做 sub.instance_eval { @my_private_field }
      • 如果你做了instance_evalsub等私有方法呢?
      猜你喜欢
      • 2013-01-15
      • 2022-06-18
      • 1970-01-01
      • 2016-02-28
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多