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

发布于 2024-10-23 17:32:25 字数 662 浏览 6 评论 0原文

假设您编写了一个类 Sup 并且我决定将其扩展为 Sub 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"

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

编辑: Java 中的等效示例 返回 “from Sup”,这就是答案也应该产生。

Suppose you write a class Sup and I decide to extend it to Sub < Sup. Not only do I need to understand your published interface, but I also need to understand your private fields. Witness this failure:

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"

The question is, what is the right way to tackle this problem? It seems a subclass should be able to use whatever fields it wants without messing up the superclass.

EDIT: The equivalent example in Java returns "from Sup", which is the answer this should produce as well.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

久夏青 2024-10-30 17:32:25

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

我不仅需要了解你
已发布接口,但我还需要
了解您的私人领域。

事实上,这是一个“官方”职位。摘自《Ruby 编程语言》一书(Matz 是作者之一):

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

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

Instance variables have nothing to do with inheritance, they are created on first usage, not by some defining mechanism, therefore there is no special access control for them in language and they can not be shadowed.

Not only do I need to understand your
published interface, but I also need
to understand your private fields.

Actually this is an "official" position. Excerpt from "The Ruby Programming Language" book (where Matz is one of the authors):

... this is another reason why it is only safe to extend Ruby
classes when you are familiar with
(and in control of) the implementation
of the superclass.

If you don't know it inside and out you're on your own. Sad but true.

走野 2024-10-30 17:32:25

不要子类化它!

使用组合而不是继承。

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

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

Don't subclass it!

Use composition instead of inheritance.

Edit: Rather than MyObject subclassing ExistingObject, see if my_object having an instance variable referring to existing_object would be more appropriate.

Instance variables belong to instances (ie objects). They're not determined by the classes themselves.

吃素的狼 2024-10-30 17:32:25

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

unlike java/C#, in ruby private variables are always visible to the inheriting classes. There is no way to hide the private variables.

一桥轻雨一伞开 2024-10-30 17:32:25

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

 class Sub
   private
   def foo; end
 end

sub.foo => error accessing private method with caller

但是如果你改变了 self 的身份,你总是可以访问它:

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 }

Ruby and Java don't treat 'private' property the same way. In Ruby if you mark something as private it only means that it can't be called with receiver, i.e.:

 class Sub
   private
   def foo; end
 end

sub.foo => error accessing private method with caller

but you can always access it if you change who is self like:

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

Conclusion: Don't rely that you can hide or protect something from outer space! Or with great power comes great responsibility!

EDIT:

Yes, I know question was for fields but it's the same thing. You can always do:

sub.instance_eval { @my_private_field = 'something else' }
puts sub.instance_eval { @my_private_field }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文