Ruby可以子类化实例变量_overwrite_超类(同名)吗?

时间:2013-01-26 13:00:55

标签: ruby inheritance subclass instance-variables superclass

在“ruby编程语言”一书的第7.3.5节“继承和实例变量”中说:

  

因为实例变量与之无关   继承,它遵循一个子类使用的实例变量不能“阴影”   超类中的实例变量。如果子类使用具有相同的实例变量   将name命名为其祖先之一使用的变量,它将覆盖其>祖先的值   变量。这可以有意地完成,以改变祖先的行为,或者它可以   无意中完成。在后一种情况下,几乎可以肯定会导致错误。和。一样   继承前面描述的私有方法,这是它的唯一原因   当您熟悉(并控制)时,可以安全地扩展Ruby类   实现超类。

我做了自己的测试,但似乎来自子类的实例变量不会影响超类

我的Ruby版

bob@bob-ruby:~$ ruby --version
ruby 1.9.3p194 (2012-04-20 revision 35410) [i686-linux]
bob@bob-ruby:~$ 

以下是代码

class Point
   attr_accessor :x,:y
   def initialize(x,y)
     @x,@y=x,y
   end
end

class Point3D < Point
   attr_accessor :x,:y,:z
   def initialize(x,y,z)
     @x=x
     @y=y
     @z=z
   end
end

irb(main):052:0> p=Point.new(1,2)
=> #<Point:0x87e8968 @x=1, @y=2>
irb(main):053:0> q=Point3D.new(4,5,6)
=> #<Point3D:0x87e423c @x=4, @y=5, @z=6>
irb(main):054:0> q.x
=> 4
irb(main):055:0> p.x
=> 1
irb(main):056:0> 

2 个答案:

答案 0 :(得分:6)

这本书(重点和补充我的):

  

如果子类使用与其祖先之一使用的[n instance]变量同名的实例变量,它将覆盖其祖先的值。变量

我知道你没有同一个班级的两个实例;我们专门讨论继承问题。

当子类使用与超类使用的实例变量同名的实例变量时,会有一个实例变量。如果子类更改了该实例变量的值,并且超类访问它,则它将获取子类设置的值。

当一个子类被实例化时,它“as-if”它的也是超类的一个实例。实现Ruby的方式意味着如果超类具有实例变量@foo,则子类可以访问它。这使得子类的@foo和超类的@foo之间的区别毫无意义。

这是子类如何改变超类行为:通过设置超类可能使用的值。如果子类设置@foo = 42,并且超类方法访问@foo,则会看到42。这可能是也可能不是,因此警告。它可能导致令人沮丧的调试会议。

class MyStack
  def initialize
    @my_array = []
  end

  def push(item)
    @my_array << item
  end
end

# Stack class that keeps a list 
# of every item ever pushed.
class TrackingStack < MyStack
  def initialize
    super
    @my_array = []
  end

  def push(item)
    super
    @my_array << item
  end

  def all_items_ever_pushed
    @my_array
  end
end

TrackingStack引入了一个错误,因为它无意中使用了与用于保存堆栈内容的超类数组相同的名称。如果您不熟悉超类的实现,那么在您深入挖掘以了解意外行为的来源之前,这将导致混淆和错误。

超类的一个实例就是:超类的实例,讨论子类的实例 是没有意义的>会影响它,因为它们完全不相关。

这是一个改写:

  

当您不控制或不熟悉超类实现时,子类化可能会有风险。一个原因是因为在子类中引入实例变量可能会覆盖超类实例变量的值,从而导致意外行为。

答案 1 :(得分:1)

实例变量属于实例,而不属于类。 “继承”的整个概念在那里甚至没有意义,继承仅适用于类。