Menu
CoddyTech

Gọi super

Thuộc phần Lập trình hướng đối tượng trong hành trình Ruby của Coddy. Bài học 24 trên 57.

Bên trong một phương thức ghi đè, super gọi phiên bản của cùng phương thức trong lớp cha. Lớp con có thể dựa trên kết quả đó thay vì lặp lại:

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

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

puts LoudGreeter.new.greet("Ada")

Đầu ra:

HELLO, ADA!

Cách dùng phổ biến nhất là initialize: lớp con nhận thêm một giá trị, truyền các giá trị chung cho lớp cha bằng super(...) rồi lưu giá trị riêng:

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}"

Đầu ra:

Ada, 20, MIT

Ba dạng này khác nhau ở các đối số được truyền. super không có ngoặc truyền các đối số mà phương thức hiện tại đã nhận; super() không truyền đối số nào; super(a, b) chỉ truyền đúng các đối số đó:

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)

Đầu ra:

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

super có thể chạy ở bất cứ đâu trong phương thức hoặc chỉ khi thỏa mãn một điều kiện. Khi initialize của lớp con nhận các đối số khác với initialize của lớp cha, super không kèm đối số sẽ truyền sai đối số, đây là nguyên nhân phổ biến gây ra 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")

Đầu ra:

LOG started
LOG done
challenge icon

Thử thách

Dễ

Hoàn thiện các lớp. Person lưu name và age, còn to_s trả về Ada (36). Student bổ sung trường học: initialize truyền tên và tuổi cho super, còn to_s trả về Ada (20), studies at MIT, được tạo từ super. Teacher bổ sung môn học theo cách tương tự và trả về Bo (45), teaches maths.

Code được cung cấp đọc các dòng person Ada 36, student Ada 20 MIT hoặc teacher Bo 45 maths rồi in ra từng đối tượng.

Code của bạn nằm trong person.rb, student.rb và teacher.rb. main.rb chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.

Tự làm thử

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

# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Ruby online