【问题标题】:Why do we use super in ruby when I can inherit without its use?当我可以不使用 super 继承时,为什么我们在 ruby​​ 中使用 super?
【发布时间】:2017-02-03 04:48:00
【问题描述】:

好的,所以我在这里搜索了这个问题的答案,但找不到我所追求的(确切地说),所以我会有点贪婪,并要求一些社区时间。我希望使我的问题尽可能适用。

因此,在某些情况下,上周我一直在为类、类变量和方法的想法而苦苦挣扎,但在过去的两天里,我的理解取得了重大进展。但是现在我面临着继承,无法弄清楚为什么当我可以不使用它就继承时使用 super 。

例如:

class Animal 
   def initialize (type, breed, age)
     @type = type
     @breed = breed
     @age = age
   end
end

class Dog < Animal
end

class Cat < Animal
end

class Fish 
end

woof = Dog.new("dog", "shitzu", 12)
meow = Cat.new("cat", "tabby", 5)
fish = Fish.new("fish", "gold", 2)

Output:

=> #<Dog:0x00000001447680 @type="dog", @breed="shitzu", @age=12> 
=> #<Cat:0x0000000140c918 @type="cat", @breed="tabby", @age=5> 
ArgumentError: wrong number of arguments (given 3, expected 0)

如您所见,我已经能够在我标记为继承的 Dog 和 Cat 类上从 Animal 继承,但在我的 Fish 上却不能,因为我没有继承。

如果有人能解释我们为什么使用 super,并指出我理解中的缺陷,我将不胜感激,我知道我可能完全误解了这里的用法,但我想澄清一下。感谢您的宝贵时间,感谢您的帮助。

ty.

【问题讨论】:

  • 您想知道对super 的显式调用吗? (比如,当一个方法调用“super”来运行其父类的方法版本时?)
  • 如果你想自定义 Dog 类中的 initialize 方法,简单地从类 Animal 继承不会让你自定义它。如果在Dog 类中,您做了类似def initialize(type, breed, age, color) 的操作,然后有super(type, breed, age) 和@color = color,这将允许您更改在super 调用其父类Animal 时继承的初始化方法初始化您拥有的其他实例变量
  • 您的意思是在示例中使用super 吗?我不明白这个问题与代码示例有什么关系。
  • @gmcnaughton 和 philip yoo(对不起,我不能在同一评论中同时标记两者)解释了它。抱歉这个愚蠢的问题,我刚刚做了一些不同的在线课程,它似乎被添加到这里和那里,但我不知道应该什么时候使用它
  • @JoshuaCheek 好吧,这是我的一半问题,公平地说我不知道​​,我有点问 super 是如何应用的,我认为它与初始化方法有关。

标签: ruby class inheritance initialization super


【解决方案1】:

摘自Inheritance - What is inherited?。原作者是nus。归属细节可以在contributor page 上找到。该源在CC BY-SA 3.0 下获得许可,可以在Documentation archive 中找到。参考主题 ID:625 和示例 ID:14883。

方法是继承的

class A
  def boo; p 'boo' end
end

class B < A; end

b = B.new
b.boo # => 'boo'

类方法被继承

class A
  def self.boo; p 'boo' end
end

class B < A; end

p B.boo # => 'boo'

常量被继承

class A
  WOO = 1
end

class B < A; end

p B::WOO # => 1

但请注意,它们可以被覆盖:

class B
  WOO = WOO + 1
end

p B::WOO # => 2

实例变量被继承:

class A
  attr_accessor :ho
  def initialize
    @ho = 'haha'
  end
end

class B < A; end

b = B.new
p b.ho # => 'haha'

请注意,如果您重写初始化实例变量的方法而不调用super,它们将为零。从上面继续:

class C < A
  def initialize; end
 end

c = C.new
p c.ho    # => nil

类实例变量不被继承:

class A
    @foo = 'foo'
    class << self
        attr_accessor :foo
    end
end

class B < A; end

p B.foo # => nil

# The accessor is inherited, since it is a class method
#
B.foo = 'fob' # possible

类变量并不是真正继承的

它们作为 1 个变量在基类和所有子类之间共享:

class A
    @@foo = 0
    def initialize
        @@foo  += 1 
        p @@foo
    end
end

class B < A;end

a = A.new # => 1
b = B.new # => 2

所以从上面继续:

class C < A
  def initialize
    @@foo = -10
    p @@foo
  end
end

a = C.new # => -10
b = B.new # => -9

【讨论】:

    【解决方案2】:

    使用super 可以让类覆盖从其父类继承的方法并对其进行自定义。

    例如,在您的示例中,Dog 和 Cat 从 Animal 继承 #initialize - 但是如果我们想要 Dog 的一些特殊逻辑怎么办?

    class Dog < Animal
      def initialize(type, breed, age)
        raise "Sorry, dogs don't live that long!" if age > 100
    
        # Everything looks good - let Animal#initialize run now
        super
      end
    end
    

    这让Dog 自定义其初始化方法的作用,但仍调用原始继承方法。

    【讨论】:

    • 是的。简而言之,它是您的子类具有“几乎但不完全”的方法的地方,就像它们的父类一样。
    • 所以我们基本上使用 super 来添加额外的功能,同时也继承现有的父功能?
    • “使用 super 让一个类覆盖它从其父类继承的方法” 具有误导性。一个类可以覆盖在其父类中定义的方法,只需在没有super 的情况下定义它。 super 从父类调用原始方法。
    • @JohnVonNeumann 是的,当场! (它不仅适用于#initialize,同样的技术适用于您想要覆盖的任何方法)。
    • 在这个例子中有一些非常微妙的东西需要操作者注意;参数列表中提供的值被隐式传递给对super 的调用。在某些情况下,需要将值显式传递给 super 方法。
    猜你喜欢
    • 2020-03-25
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    相关资源
    最近更新 更多