Menu
CoddyTech

调用 super

本课属于 Coddy Ruby 学习旅程的“面向对象编程”单元。第 24 课,共 57 课。

在重写的方法中,super 会调用超类中同一方法的版本。子类可以在结果的基础上进行扩展,而不是重复实现:

class Greeter
  def greet(name)
    "Hello, #{name}"
  end
end

class LoudGreeter < Greeter
  def greet(name)
    super.upcase + "!"
  end
end

puts LoudGreeter.new.greet("Ada")

输出:

HELLO, ADA!

最常见的用法是 initialize:子类会接收一个额外的值,将共有的值传给父类,并用 super(...) 保存自己的值:

class Person
  attr_reader :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end
end

class Student < Person
  attr_reader :school

  def initialize(name, age, school)
    super(name, age)
    @school = school
  end
end

s = Student.new("Ada", 20, "MIT")
puts "#{s.name}, #{s.age}, #{s.school}"

输出:

Ada, 20, MIT

这三种形式传递的参数不同。不带括号的 super 会传递当前方法收到的相同参数;super() 不传递任何参数;super(a, b) 则只传递这两个参数:

class Base
  def show(*args)
    "Base got #{args.inspect}"
  end
end

class Child < Base
  def show(a, b)
    [super, super(), super(b)].join(" | ")
  end
end

puts Child.new.show(1, 2)

输出:

Base got [1, 2] | Base got [] | Base got [2]

super 可以在方法中的任何位置运行,也可以只在满足某个条件时运行。如果子类的 initialize 接收的参数与父类不同,那么裸写 super 会传递错误的参数,这会导致常见的 ArgumentError:

class Logger
  def log(message)
    puts "LOG #{message}"
  end
end

class QuietLogger < Logger
  def log(message)
    super unless message.start_with?("debug")
  end
end

logger = QuietLogger.new
logger.log("started")
logger.log("debug x=1")
logger.log("done")

输出:

LOG started
LOG done
challenge icon

挑战

简单

完成这些类。Person 会存储 name 和 age,它的 to_s 会返回 Ada (36)。Student 会添加学校信息:它的 initialize 会将姓名和年龄传给 super,它的 to_s 会根据 super 返回 Ada (20), studies at MIT。Teacher 以相同的方式添加学科信息,并返回 Bo (45), teaches maths。

提供的代码会读取以下行:person Ada 36、student Ada 20 MIT 或 teacher Bo 45 maths,并打印每个对象。

你的代码应写在 person.rb、student.rb 和 teacher.rb 中。main.rb 包含提供的输入/输出代码,不能编辑。

亲手试试

require_relative 'person'
require_relative 'student'
require_relative 'teacher'

# 提供的输入输出代码:保持原样
input = []
while (line = gets)
  input << line.chomp
end
input.each do |line|
  kind, name, age, extra = line.split
  person = case kind
           when "student" then Student.new(name, age.to_i, extra)
           when "teacher" then Teacher.new(name, age.to_i, extra)
           else Person.new(name, age.to_i)
           end
  puts person
end
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Ruby 在线编译器