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